﻿#include "SemanticAnalyzer.h"



#include "ScriptCompiler/Description/DecoratedTypeDescription.h"
#include "ScriptCompiler/Description/ParameterDescription.h"
#include "ScriptCompiler/Description/FunctionDescription.h"
#include "ScriptCompiler/Description/TypeDescription.h"
#include "ScriptCompiler/Description/NamespaceDescription.h"
#include "ScriptCompiler/Description/FieldDescription.h"
#include "ScriptCompiler/Description/PropertyDescription.h"
#include "ScriptCompiler/Description/DecoratorDescription.h"
#include "ScriptCompiler/Description/FunctionBodyDescription.h"
#include "ScriptCompiler/Description/VariableDescription.h"
#include "ScriptCompiler/Description/UsingDescription.h"
#include "ScriptCompiler/Description/DecoratorDescription.h"
#include "ScriptCompiler/Description/ConstructorDescription.h"


#include "ScriptCompiler/CompilerContext.h"
#include "ScriptCompiler/ScriptFileContext.h"
#include "ScriptRuntime/Type/ConstantValue.h"
#include "FunctionContext.h"
#include "StatementContext.h"
#include "ExpressionContext.h"

#include "ScriptCompiler/Token/Token.h"
#include "Reflection/Class.h"
#include "Reflection/ObjectPtr.h"
#include "Reflection/Function.h"
#include "Reflection/FunctionList.h"
#include "Reflection/GenericInfo.h"
#include "Reflection/PropertyList.h"
#include "Reflection/WeakObjectPtr.h"
#include "Reflection/FunctionType.h"

#include "ScriptCompiler/AST/NamespaceNode.h"
#include "ScriptCompiler/AST/ClassNode.h"
#include "ScriptCompiler/AST/EnumNode.h"
#include "ScriptCompiler/AST/EnumValueNode.h"
#include "ScriptCompiler/AST/DelegateNode.h"
#include "ScriptCompiler/AST/FunctionNode.h"
#include "ScriptCompiler/AST/ParameterNode.h"
#include "ScriptCompiler/AST/TypeNode.h"
#include "ScriptCompiler/AST/AccessLevelNode.h"
#include "ScriptCompiler/AST/FieldNode.h"
#include "ScriptCompiler/AST/PropertyNode.h"
#include "ScriptCompiler/AST/DecoratorNode.h"
#include "ScriptCompiler/AST/FunctionCallNode.h"
#include "ScriptCompiler/AST/IfNode.h"
#include "ScriptCompiler/AST/WhileNode.h"
#include "ScriptCompiler/AST/DoWhileNode.h"
#include "ScriptCompiler/AST/ForNode.h"
#include "ScriptCompiler/AST/ReturnNode.h"
#include "ScriptCompiler/AST/VariableDeclarationNode.h"
#include "ScriptCompiler/AST/ValueNode.h"
#include "ScriptCompiler/AST/SwitchNode.h"
#include "ScriptCompiler/AST/CaseNode.h"
#include "ScriptCompiler/AST/BreakNode.h"
#include "ScriptCompiler/AST/ContinueNode.h"
#include "ScriptCompiler/AST/BracketNode.h"
#include "ScriptCompiler/AST/GetAccessorNode.h"
#include "ScriptCompiler/AST/SetAccessorNode.h"
#include "ScriptCompiler/AST/LiteralNode.h"
#include "ScriptCompiler/AST/IdentifierNode.h"
#include "ScriptCompiler/AST/BinocularOperatorNode.h"
#include "ScriptCompiler/AST/MonocularOperatorNode.h"
#include "ScriptCompiler/AST/MemberAccessNode.h"
#include "ScriptCompiler/AST/AssignNode.h"
#include "ScriptCompiler/AST/SentenceBlockNode.h"
#include "ScriptCompiler/AST/UsingNode.h"
#include "ScriptCompiler/AST/NewNode.h"
#include "ScriptCompiler/AST/ConstructorNode.h"
#include "ScriptCompiler/AST/ForNode.h"
#include "ScriptCompiler/AST/PropertyIndexerNode.h"
#include "ScriptCompiler/AST/SentenceIndexerNode.h"
#include "ScriptCompiler/AST/FunctionContentNode.h"
#include "ScriptCompiler/AST/ExpressionSentence.h"
#include "ScriptCompiler/AST/PositiveNode.h"
#include "ScriptCompiler/AST/NegativeNode.h"
#include "ScriptCompiler/AST/ParenthesesNode.h"
#include "ScriptCompiler/AST/TypeCastNode.h"



#include "ScriptCompiler/FrameOperation/LoadLiteralOperation.h"
#include "ScriptCompiler/FrameOperation/LoadVariableOperation.h"
#include "ScriptCompiler/FrameOperation/LoadVariableAddressOperation.h"
#include "ScriptCompiler/FrameOperation/StoreVariableOperation.h"
#include "ScriptCompiler/FrameOperation/StoreFieldOperation.h"
#include "ScriptCompiler/FrameOperation/LoadFieldOperation.h"
#include "ScriptCompiler/FrameOperation/LoadFieldAddressOperation.h"
#include "ScriptCompiler/FrameOperation/FunctionCallOperation.h"
#include "ScriptCompiler/FrameOperation/LoadArgumentOperation.h"
#include "ScriptCompiler/FrameOperation/LoadArgumentAddressOperation.h"
#include "ScriptCompiler/FrameOperation/StoreArgumentOperation.h"
#include "ScriptCompiler/FrameOperation/BoxInnerTypeOperation.h"
#include "ScriptCompiler/FrameOperation/NewObjectOperation.h"
#include "ScriptCompiler/FrameOperation/ConstructorCallOperation.h"
#include "ScriptCompiler/FrameOperation/VirtualFunctionCallOperation.h"
#include "ScriptCompiler/FrameOperation/ReturnOperation.h"
#include "ScriptCompiler/FrameOperation/JumpOperation.h"
#include "ScriptCompiler/FrameOperation/DoNothingOperation.h"
#include "ScriptCompiler/FrameOperation/SimpleInstructionOperation.h"
#include "ScriptCompiler/FrameOperation/SwitchOperation.h"
#include "ScriptCompiler/FrameOperation/InnerTypeConvertionOperation.h"
#include "ScriptCompiler/FrameOperation/InitValueTypeOperation.h"
#include "ScriptCompiler/FrameOperation/LoadFunctionOperation.h"
#include "ScriptCompiler/FrameOperation/DynamicCastClassOperation.h"

#include <functional>

#include "Reflection/NullObjectPtr.h"

#include "Math/MathBase.h"

#include "Widgets/WidgetAttribute.h"
#include "Math/Color.h"

std::shared_ptr<CNamespaceDescription> CSemanticAnalyzer::FindOrAddChildeNamespace(std::shared_ptr<CNamespaceDescription> InParentNamespace ,const TVector<CString>& SubPath)
{
    for (auto& Namespace :InParentNamespace->Namespaces)
    {
        if (Namespace->GetSearchName() == SubPath[0])
        {
            if(SubPath.Num() == 1)
            {
                return Namespace;
            }
            return FindOrAddChildeNamespace(Namespace,SubPath.Slice(1, SubPath.size() - 1));
        }
    }
    
    auto New= std::make_shared<CNamespaceDescription>();
    New->ParentScope = InParentNamespace;
    New->FullNameChain = InParentNamespace->FullNameChain;
    New->FullNameChain.Add(SubPath[0]);
    InParentNamespace->Namespaces.Add(New);
    //New->IndexInParent = InParentNamespace->Namespaces.Num() - 1;

    for(uint64_t i=1;i<SubPath.size();i++)
    {
        auto Child = std::make_shared<CNamespaceDescription>();
        Child->ParentScope = New;
        Child->FullNameChain = New->FullNameChain;
        Child->FullNameChain.Add(SubPath[i]);
        New->Namespaces.Add(Child);
        //Child->IndexInParent = New->Namespaces.Num() - 1;
        New = Child;
    }

    return New;
}

std::shared_ptr<CGSharpFieldDescription> CSemanticAnalyzer
    ::FindFieldByName(std::shared_ptr<CTypeDescription> InClass, const CString &InFieldName)
{
    for (auto& Field :InClass->Fields)
    {
        if (Field->GetSearchName() == InFieldName)
        {
            return Field;
        }
    }

    if (InClass->BaseClass)
    {
        return FindFieldByName(InClass->BaseClass, InFieldName);
    }

    return nullptr;
}

STypeID CSemanticAnalyzer::CreateNonGenerailizedTypeID(const TVector<CString> &InParentScopeNameChain, const CString &Name)
{
    return STypeID(InParentScopeNameChain, Name, false);
}

std::shared_ptr<CTypeDescription> CSemanticAnalyzer::GetNativeTypeIdentifier(CType* InType)
{
    assert(InType);

    assert(InType->CanUseInScript()); //dont support weak object ptr

    if(InType->IsClassType())
    {
        CClass* ClassType= static_cast<CClass*>(InType);
        return FindClassByID(ClassType->SharedPtrType->ID);
    }

    return FindClassByID(InType->ID);
}

bool CSemanticAnalyzer::HaveSameSignature(std::shared_ptr<CFunctionDescription> A, std::shared_ptr<CFunctionDescription> B)
{
    if(A->GetFunctionName()!= B->GetFunctionName())
    {
        return false;
    }

    if(A->Parameters.Num() != B->Parameters.Num())
    {
        return false;
    } 

    for(int32_t i= 0; i< A->Parameters.Num(); i++)
    {
        if(!A->Parameters[i]->Type.IsSameWith(B->Parameters[i]->Type))
        {
            return false;
        }
    }

    return true;
}

SDecoratedTypeDescription CSemanticAnalyzer::FindOrCreateFunctionType(
    SDecoratedTypeDescription InReturnType
    , TVector<SDecoratedTypeDescription> InParameters
    )
{

    SGenericTypeArgumentGroup AllTypes;
    AllTypes.Arguments.Add(InReturnType);
    AllTypes.Arguments.Append(InParameters);

    auto Found=FunctionTypeDescriptions.Find(AllTypes);
    if(Found)
    {
        return *Found;
    }

    auto NewType= SDecoratedTypeDescription();
    NewType.BasicType =  std::make_shared<CTypeDescription>();
    NewType.BasicType->MarkAsFunctionPointer();
    
    NewType.BasicType->FunctionPointerReturnType = InReturnType;
    NewType.BasicType->FunctionPointerParameters = InParameters;

    {
        TVector<CString> Names;
        Names.Reserve(InParameters.Num());
        for(auto& Param : InParameters)
        {
            Names.Add(Param.ToString());
        }

        NewType.BasicType->Name=
            CFunctionType::CreateTypeName(InReturnType.ToString(),Names);
    }

    NewType.BasicType->ParentScope =Context->GlobalNamespace;
    NewType.BasicType->ParentScopeNameChain=Context->GlobalNamespace->FullNameChain;

    TVector<STypeID> InParametersTypeID;
    for(auto& Param: InParameters)
    {
        InParametersTypeID.Add(Param.BasicType->TypeID);
    }

    NewType.BasicType->TypeID= CFunctionType::CreateID(
        InReturnType.BasicType->TypeID
        ,InParametersTypeID
    );

    AddScriptClass(NewType.BasicType);
    
    NewType.BasicType->IndexInParent = Context->GlobalNamespace->Classes.Num();
    Context->GlobalNamespace->Classes.Add(NewType.BasicType);
    

    FunctionTypeDescriptions.Add(AllTypes, NewType);
    return NewType;
}

SDecoratedTypeDescription CSemanticAnalyzer::FindOrCreateFunctionTypeWithParameter(
    SDecoratedTypeDescription InReturnType
    , TVector<std::shared_ptr<CParameterDescription>> InParameters
    )
{
    TVector<SDecoratedTypeDescription> ParameterTypes;

    for(auto& Param: InParameters)
    {
        ParameterTypes.Add(Param->Type);
    }

    return FindOrCreateFunctionType(InReturnType,ParameterTypes);
}

SDecoratedTypeDescription CSemanticAnalyzer::FindOrCreateDelegateType(SDecoratedTypeDescription InFunctionType)
{
    assert(InFunctionType.BasicType->IsFunctionPointer());

    TVector<STypeID> AllParameterIDs;
    for(auto& Param: InFunctionType.BasicType->FunctionPointerParameters)
    {
        AllParameterIDs.Add(Param.BasicType->TypeID);
    }

    auto DelgateID= 
        CScriptDelegateType::CreateID(
            InFunctionType.BasicType->FunctionPointerReturnType.BasicType->TypeID
            ,AllParameterIDs
        );

    //1. find delegate type in global namespace
    std::shared_ptr<CTypeDescription> DelegateClass;
    for(auto& Class: Context->GlobalNamespace->Classes)
    {
        if(Class->TypeID==DelgateID)
        {
            DelegateClass=Class;
            break;
        }
    }

    if(!DelegateClass)
    {
        //2. create delegate type
        DelegateClass= std::make_shared<CTypeDescription>();
        DelegateClass->MarkAsDelegate();
        

        DelegateClass->TypeID= DelgateID;

        AddScriptClass(DelegateClass);

        SGenericTypeArgumentGroup GenerializeDelegateArgs;
        GenerializeDelegateArgs.Arguments.Add(InFunctionType.BasicType->FunctionPointerReturnType);
        GenerializeDelegateArgs.Arguments.Append(InFunctionType.BasicType->FunctionPointerParameters);

        GenerializeClass(
            DelegateClass
            ,GenericDelegateClassDescription
            ,GenerializeDelegateArgs
            ,Context
        );
    }

    auto Type= SDecoratedTypeDescription();
    Type.BasicType=DelegateClass;
    return Type;
}

void CSemanticAnalyzer::Analysis(std::shared_ptr<CCompilerContext> InContext)
{
    Context=InContext;

    //1. create global namespace
    auto GlobalNamespace = std::make_shared<CNamespaceDescription>();
    InContext->GlobalNamespace=GlobalNamespace;

    //3.collect all native class and fill inner type description
    CollectNativeClasses(InContext);


    //create script namespace
    for(auto ScriptFile: InContext->ScriptFiles.Values())
    {
        GlobalNamespace->ASTNodes.Add(ScriptFile->ASTRoot);
    }

    for(auto ScriptFile: InContext->ScriptFiles.Values())
    {
        CreateScriptNamespaces(ScriptFile);
    }

    //create script using 
    for(auto ScriptFile: InContext->ScriptFiles.Values())
    {
        if(!CreateUsing(ScriptFile))
        {
            return;
        }
    } 

    //create script classes
    for(auto ScriptFile: InContext->ScriptFiles.Values())
    {
        if(!CreateScriptClasses(ScriptFile))
        {
            return;
        }
    }

    //5. Derivation class level types, such as deleget's return type and parameter type 
    for(auto ScriptFile: InContext->ScriptFiles.Values())
    {
        if(!CreateClassLevelTypes(ScriptFile))
        {
            return;
        }
    }

    //5.determine the base class
    for(auto ScriptFile: InContext->ScriptFiles.Values())
    {
        if(!DetermineBaseClass(ScriptFile))
        {
            return;
        }
    }

    //**************class level work finished*************

    //6. create script class member
    for(auto ScriptFile: InContext->ScriptFiles.Values())
    {
        if(!CreateClassMembers(ScriptFile))
        {
            return;
        }
    }

    //7. Initialize static field
    for(auto ScriptFile: InContext->ScriptFiles.Values())
    {
        if(!InitConstantFields(ScriptFile))
        {
            return;
        }
    }


    //8. create all virtual function table
    if(!InitVirtualFunctionTable(GlobalNamespace,InContext))
    {
        return;
    }

    //9. create all function content
    for(auto ScriptFile: InContext->ScriptFiles.Values())
    {
        if(!FillFunctionBody(ScriptFile))
        {
            return;
        }
    }


    InContext->ScriptClasses=ScriptClassesInOrder;

}

void CSemanticAnalyzer::CreateScriptNamespaces(std::shared_ptr<CScriptFileContext> InFileContext)
{
    //create namespaces
    std::stack<std::shared_ptr<CNamespaceDescription>> NamespaceStack;
    NamespaceStack.push(Context->GlobalNamespace);

    std::stack<std::shared_ptr<CNamespaceNode>> NamespaceNodeStack;
    NamespaceNodeStack.push(InFileContext->ASTRoot);

    while(!NamespaceStack.empty())
    {
        auto Namespace=NamespaceStack.top();
        NamespaceStack.pop();

        auto NamespaceNode=NamespaceNodeStack.top();
        NamespaceNodeStack.pop();


        for(auto& SubNamespaceNode: NamespaceNode->Namespaces)
        {
            for(int32_t ChainIndex=0;ChainIndex< SubNamespaceNode->NameChain.Num();ChainIndex++)
            {
                auto SubNamespaceName=SubNamespaceNode->NameChain[ChainIndex]->ToString();
                auto SubNamespace=Namespace->FindNamespace(SubNamespaceName);
                if(!SubNamespace)
                {
                    SubNamespace=std::make_shared<CNamespaceDescription>();
                    SubNamespace->FullNameChain=Namespace->FullNameChain;
                    SubNamespace->FullNameChain.Add(SubNamespaceName);
                    SubNamespace->ParentScope=Namespace;

                    if(ChainIndex==SubNamespaceNode->NameChain.Num()-1)
                    {
                        SubNamespace->ASTNodes.Add(SubNamespaceNode);
                    }

                    Namespace->Namespaces.Add(SubNamespace);
                }
                else
                {
                    SubNamespace->ASTNodes.Add(SubNamespaceNode);
                }

                NamespaceStack.push(SubNamespace);
                NamespaceNodeStack.push(SubNamespaceNode);
            }
        }

    }

}

bool CSemanticAnalyzer::CreateUsing(std::shared_ptr<CScriptFileContext> InFileContext)
{
    std::stack<std::shared_ptr<CNamespaceDescription>> NamespaceStack;
    NamespaceStack.push(Context->GlobalNamespace);

    std::stack<std::shared_ptr<CNamespaceNode>> NamespaceNodeStack;
    NamespaceNodeStack.push(InFileContext->ASTRoot);

    std::function<bool (std::shared_ptr<CNamespaceNode>)> CreateUsing=[&](
        std::shared_ptr<CNamespaceNode> InNamespaceNode)->bool 
    {

        //find using namespace
        for(auto& Using: InNamespaceNode->Usings)
        {
            CString FirstNamespaceName= Using->NameChain[0]->ToString();

            //find first using namespace
            std::shared_ptr<CNamespaceDescription> CurrentNamespace=
                NamespaceStack.top()->FindNamespaceInFile(InFileContext,FirstNamespaceName);

            if(!CurrentNamespace)
            {
                InFileContext->RaiseError(20001,Using->NameChain[0],
                    U"Can't find namespace "+FirstNamespaceName);
                return false;
            }

            //find sub namespace
            for(uint32_t NameChainIndex=1; NameChainIndex<Using->NameChain.Num();NameChainIndex++)
            {
                auto SubNamespaceName=Using->NameChain[NameChainIndex]->ToString();
                auto SubNamespace=CurrentNamespace->FindNamespace(SubNamespaceName);
                if(!SubNamespace)
                {
                    //raise error,cant find namespace
                    InFileContext->RaiseError(20002,Using->NameChain[NameChainIndex],
                        U"Can't find namespace "+SubNamespaceName);
                    return false;
                }
                CurrentNamespace=SubNamespace;
            }

            bool bFileContextExist=false;
            for(auto UsingNamespacePair: NamespaceStack.top()->UsingNamespaces)
            {
                if(UsingNamespacePair.First.lock()!=InFileContext)
                {
                    continue;
                }
                bFileContextExist=true;
                UsingNamespacePair.Second.AddUnique(CurrentNamespace);
                break;
            }

            if(!bFileContextExist)
            {
                NamespaceStack.top()->UsingNamespaces.Add(
                    WH::MakeTuple(
                        std::weak_ptr<CScriptFileContext>(InFileContext)
                        ,TVector<std::shared_ptr<CNamespaceDescription>>({CurrentNamespace})
                    )
                );
            }

        }

        for(auto SubNamespaceNode:InNamespaceNode->Namespaces)
        {
            //find namespace
            for(auto & NamespaceName: SubNamespaceNode->NameChain)
            {
                auto Namespace=NamespaceStack.top()->FindNamespace(NamespaceName->ToString());
                assert(Namespace && "namespace should be created in the former stage" );
                NamespaceStack.push(Namespace);
                
                NamespaceNodeStack.push(SubNamespaceNode);
 
            }

            for(auto& SubNamespaceNode: SubNamespaceNode->Namespaces)
            {
                if(!CreateUsing(SubNamespaceNode))
                {
                    return false;
                }
            }


            //pop namespace stack
            for(int i=0;i<SubNamespaceNode->NameChain.Num();i++)
            {
                NamespaceStack.pop();
                NamespaceNodeStack.pop();
            }
        }

        return true;

    };

    bool Succeed=CreateUsing(InFileContext->ASTRoot);

    return Succeed;    

}

bool CSemanticAnalyzer::CreateScriptClasses(std::shared_ptr<CScriptFileContext> InFileContext)
{
    std::stack<std::shared_ptr<CNamespaceDescription>> NamespaceStack;
    NamespaceStack.push(Context->GlobalNamespace);

    std::stack<std::shared_ptr<CTypeDescription>> ClassStack;

    //iteral all namespace
    while(!NamespaceStack.empty())
    {
        auto Namespace=NamespaceStack.top();
        NamespaceStack.pop();

        for(auto& ASTNode : Namespace->ASTNodes)
        {
            for(auto& ClassNode: ASTNode->Classes)
            {
                if(ClassNode->File.lock()!=InFileContext)
                {
                    continue;
                }

                auto NewClass=CreateClassDescription(
                    Namespace->FullNameChain
                    , Namespace
                    , ClassNode
                    ,InFileContext);

                if(!NewClass)
                {
                    return false;
                }      

                ClassStack.push(NewClass);

            }

            for(auto & DelegateNode : ASTNode->Delegates)
            {
                if(DelegateNode->File.lock()!=InFileContext)
                {
                    continue;
                }

                auto NewClass=CreateDelegateDescription(
                    //Namespace->FullNameChain
                    //,
                    Namespace
                    //, Namespace->Classes
                    , DelegateNode
                    ,InFileContext);

                if(!NewClass)
                {
                    return false;
                }      

                //NameSearchTreeNode->AddChild(NewClass);
            }

            for(auto & Enum :ASTNode->Enums)
            {
                if(Enum->File.lock()!=InFileContext)
                {
                    continue;
                }

                auto NewClass=CreateEnumDescription(
                    Namespace->FullNameChain
                    , Namespace->Classes
                    , Enum
                    ,InFileContext);

                if(!NewClass)
                {
                    return false;
                }    

            }
        }

        //add sub namespace into stack
        for(auto& SubNamespace: Namespace->Namespaces)
        {
            NamespaceStack.push(SubNamespace);
        }

    }

    //iteral all classes
    while(!ClassStack.empty())
    {
        auto Class=ClassStack.top();
        ClassStack.pop();

        //create class in class
        assert(Class->ClassNode);

        for(auto& SubClassNode: Class->ClassNode->Classes)
        {
            TVector<CString> ClassFullNameChain=Class->ParentScopeNameChain;
            ClassFullNameChain.Add(Class->Name);

            auto NewClass=CreateClassDescription(
                ClassFullNameChain
                , Class
                , SubClassNode
                ,InFileContext);

            if(!NewClass)
            {
                return false;
            }   

            ClassStack.push(NewClass);
        }

        for(auto& Delgate: Class->ClassNode->Delegates)
        {
            auto NewClass=CreateDelegateDescription(
                Class
                ,Delgate
                ,InFileContext);

            if(!NewClass)
            {
                return false;
            }   
        }

        for(auto& Enum: Class->ClassNode->Enums)
        {
            TVector<CString> ClassFullNameChain=Class->ParentScopeNameChain;
            ClassFullNameChain.Add(Class->Name);

            auto NewClass=CreateEnumDescription(
                ClassFullNameChain
                , Class->Classes
                , Enum
                ,InFileContext);

            if(!NewClass)
            {
                return false;
            }   

        }
    }

    return true;
}

void CSemanticAnalyzer::CollectNativeClasses(std::shared_ptr<CCompilerContext> InContext)
{
    auto GlobalNamespace = InContext->GlobalNamespace;

    //add native namespace
    
    auto NativeNamespace = std::make_shared<CNamespaceDescription>();
    NativeNamespace->bIsNative = true;
    NativeNamespace->ParentScope = GlobalNamespace;
    NativeNamespace->FullNameChain.Add(U"Engine");
    GlobalNamespace->Namespaces.Add(NativeNamespace);


    //比如：
    //class A
    //{
    //    void Func(A a);
    //}
    //这里的A是一个普通类型，Func的指针类型依赖A，所以底层需要先创建普通类型CType，再创建函数指针类型的CType
    //也就是说A的CType 在Func的CType之前创建
    //在填充ClassDescription时， 如果先填充A的ClassDescription，再填充Func的ClassDescription,
    //会导致A中的Func的指针类型的CType找不到
    //所以先填充函数指针类型的ClassDescription

    //1.just create class description for native type,without initialize it
    //cant initialize it now, because the base class may not be created,and some (field/function parameter/..) type's class description may not be created
    const TVector<CType*>& NativeTypes = CType::GetTypeTable().GetAllNativeTypes();
    TVector<CType*> AllScriptTypes;

    for(CType* Type: NativeTypes)
    {
        if(Type->IsDependsOnEditor())
        {
            continue;
        }

        if(!Type->CanUseInScript())
        {
            //skip weak object ptr
            continue;
        }

        if(Type->IsSharedObjectPtrType())
        {
            //skip shared object ptr, use raw pointer type as shared object ptr type
            continue;
        }
        
        std::shared_ptr<CTypeDescription> NativeClass= std::make_shared<CTypeDescription>();
        AllScriptTypes.Add(Type);

        if(Type->IsClassType())
        {
            NativeClass->RawClassTypeID= Type->ID;  
            CClass* ClassType= static_cast<CClass*>(Type); 
            NativeClass->TypeID = ClassType->SharedPtrType->ID;
        }
        else
        {
            NativeClass->TypeID = Type->ID;
        }
        assert(!NativeClasses.Contains(NativeClass->TypeID));
        NativeClasses.Add(NativeClass->TypeID,NativeClass);

        NativeClass->bIsNative = true;


        if(Type== RObject::StaticClass())
        {
            ObjectDescription=NativeClass;
            NativeClass->InnerType = EScriptInnerType::Object;
            NativeClass->MarkAsInnerType();

            ObjectTypeDescription= SDecoratedTypeDescription();
            ObjectTypeDescription.BasicType=ObjectDescription;
        }
        else if(Type == CScriptDelegateType::GetStaticType())
        {
            GenericDelegateClassDescription = NativeClass;
            GenericDelegateClassDescription->MarkAsDelegate();
        }
        else if(Type == CFunctionType::GetStaticType())
        {
            GenericFunctionPtrDescription = NativeClass;
            GenericFunctionPtrDescription->MarkAsFunctionPointer();
        }
        else if(Type== CGetType<int64_t>()())
        {
            Int64Description=NativeClass;
            NativeClass->InnerType = EScriptInnerType::Int64;
            NativeClass->MarkAsInnerType();

            Int64TypeDescription= SDecoratedTypeDescription();
            Int64TypeDescription.BasicType=Int64Description;
        }
        else if(Type== CGetType<int32_t>()())
        {
            Int32Description = NativeClass;
            NativeClass->InnerType = EScriptInnerType::Int32;
            NativeClass->MarkAsInnerType();

            Int32TypeDescription= SDecoratedTypeDescription();
            Int32TypeDescription.BasicType=Int32Description;
        }
        else if(Type== CGetType<int16_t>()())
        {
            ShortDescription=NativeClass;
            NativeClass->InnerType = EScriptInnerType::Int16;
            NativeClass->MarkAsInnerType();

            ShortTypeDescription= SDecoratedTypeDescription();
            ShortTypeDescription.BasicType=ShortDescription;
        }
        else if(Type== CGetType<int8_t>()())
        {
            SbyteDescription = NativeClass;
            NativeClass->InnerType = EScriptInnerType::Int8;
            NativeClass->MarkAsInnerType();

            SbyteTypeDescription= SDecoratedTypeDescription();
            SbyteTypeDescription.BasicType=SbyteDescription;
        }
        else if(Type== CGetType<uint64_t>()())
        {
            Uint64Description=NativeClass;
            NativeClass->InnerType = EScriptInnerType::Uint64;
            NativeClass->MarkAsInnerType();

            Uint64TypeDescription= SDecoratedTypeDescription();
            Uint64TypeDescription.BasicType=Uint64Description;
        }
        else if(Type== CGetType<uint32_t>()())
        {
            Uint32Description= NativeClass;
            NativeClass->InnerType = EScriptInnerType::Uint32;
            NativeClass->MarkAsInnerType();

            Uint32TypeDescription= SDecoratedTypeDescription();
            Uint32TypeDescription.BasicType=Uint32Description;
        }
        else if(Type== CGetType<uint16_t>()())
        {
            UshortDescription= NativeClass;
            NativeClass->InnerType = EScriptInnerType::Uint16;
            NativeClass->MarkAsInnerType();

            UshortTypeDescription= SDecoratedTypeDescription();
            UshortTypeDescription.BasicType=UshortDescription;
        }
        else if(Type== CGetType<uint8_t>()())
        {
            ByteDescription= NativeClass;
            NativeClass->InnerType = EScriptInnerType::Uint8;
            NativeClass->MarkAsInnerType();

            ByteTypeDescription= SDecoratedTypeDescription();
            ByteTypeDescription.BasicType=ByteDescription;
        }
        else if(Type== CGetType<float>()())
        {
            FloatDescription= NativeClass;
            NativeClass->InnerType = EScriptInnerType::Float;
            NativeClass->MarkAsInnerType();

            FloatTypeDescription= SDecoratedTypeDescription();
            FloatTypeDescription.BasicType=FloatDescription;
        }
        else if(Type== CGetType<double>()())
        {
            DoubleDescription= NativeClass;
            NativeClass->InnerType = EScriptInnerType::Double;
            NativeClass->MarkAsInnerType();

            DoubleTypeDescription= SDecoratedTypeDescription();
            DoubleTypeDescription.BasicType=DoubleDescription;
        }
        else if(Type== CGetType<bool>()())
        {
            BoolDescription = NativeClass;
            NativeClass->InnerType = EScriptInnerType::Bool;
            NativeClass->MarkAsInnerType();

            BoolTypeDescription= SDecoratedTypeDescription();
            BoolTypeDescription.BasicType=BoolDescription;
        }
        else if(Type== CGetType<char32_t>()())
        {
            CharDescription= NativeClass;
            NativeClass->InnerType = EScriptInnerType::Char;
            NativeClass->MarkAsInnerType();

            CharTypeDescription= SDecoratedTypeDescription();
            CharTypeDescription.BasicType=CharDescription;
        }
        else if(Type== CGetType<CString>()())
        {
            StringDescription= NativeClass;
            NativeClass->InnerType = EScriptInnerType::String;
            NativeClass->MarkAsInnerType();

            StringTypeDescription= SDecoratedTypeDescription();
            StringTypeDescription.BasicType=StringDescription;
        }
        else if(Type==CNullObjectPtr::GetType())
        {
            NullObjectDescription=NativeClass;
            NativeClass->InnerType = EScriptInnerType::NullObject;
            NativeClass->MarkAsInnerType();

            NullObjectTypeDescription= SDecoratedTypeDescription();
            NullObjectTypeDescription.BasicType=NullObjectDescription;
        }
        else if(Type==CGetType<std::nullptr_t>()())
        {
            NullPtrDescription=NativeClass;
            NativeClass->InnerType = EScriptInnerType::NullPtr;
            NativeClass->MarkAsInnerType();

            NullPtrTypeDescription= SDecoratedTypeDescription();
            NullPtrTypeDescription.BasicType=NullPtrDescription;
        }
        else if(Type==CGetType<void>()())
        {
            VoidTypeDescription= SDecoratedTypeDescription();
            VoidTypeDescription.BasicType=NativeClass;
            NativeClass->InnerType = EScriptInnerType::Void;
            NativeClass->MarkAsInnerType();

        }
        
        

    };

    //2.fill function type class description
    for(CType* Type: AllScriptTypes)
    {
        if(!Type->IsFunctionType() )
        {
            //skip non function type
            continue;
        }

        std::shared_ptr<CTypeDescription> NativeClass= GetNativeTypeIdentifier(Type);
        
        NativeClass->ParentScope =NativeNamespace;
        NativeClass->ParentScopeNameChain.Add(U"Engine");
        NativeClass->IndexInParent = NativeNamespace->Classes.Num() - 1;
        NativeNamespace->Classes.Add(NativeClass);


        if(Type->IsGeneralizedType())
        {   
            std::shared_ptr<CTypeDescription> TemplateClass= 
                GetNativeTypeIdentifier(Type->GeneralizedInfo->TemplateType);
            assert(TemplateClass && "template class must create before generalized class" );
 
            SGenericTypeArgumentGroup ArgumentGroup;
            for(auto ArgumentType: Type->GeneralizedInfo->TypeArguments)
            {
                auto ArgumentClass =GetNativeTypeIdentifier(ArgumentType);
                assert(ArgumentClass && "argument class must create before generalized class" );

                SDecoratedTypeDescription ArgumentTypeDescription = SDecoratedTypeDescription();
                ArgumentTypeDescription.BasicType=ArgumentClass;
                ArgumentGroup.Arguments.Add(ArgumentTypeDescription);
            }

            //TemplateClass->GeneralizedClasses.Add(ArgumentGroup,NativeClass);
            GenerializeClass(NativeClass,TemplateClass,ArgumentGroup,InContext);
            
            continue;
        }

    }

    //3.fill native class description
    for(CType* Type: AllScriptTypes)
    {
        if(Type->IsSharedObjectPtrType())
        {
            //skip shared object ptr, use raw pointer type as shared object ptr type
            continue;
        }

        if(Type->IsFunctionType() )
        {
            //skip function type, already filled
            continue;
        }

        std::shared_ptr<CTypeDescription> NativeClass= GetNativeTypeIdentifier(Type);



        // add generalized type
        if(Type->IsGeneralizedType())
        {   
            std::shared_ptr<CTypeDescription> TemplateClass= 
                GetNativeTypeIdentifier(Type->GeneralizedInfo->TemplateType);
            assert(TemplateClass && "template class must create before generalized class" );
 
            SGenericTypeArgumentGroup ArgumentGroup;
            for(auto ArgumentType: Type->GeneralizedInfo->TypeArguments)
            {
                auto ArgumentClass =GetNativeTypeIdentifier(ArgumentType);
                assert(ArgumentClass && "argument class must create before generalized class" );

                SDecoratedTypeDescription ArgumentTypeDescription = SDecoratedTypeDescription();
                ArgumentTypeDescription.BasicType=ArgumentClass;
                ArgumentGroup.Arguments.Add(ArgumentTypeDescription);
            }

            //TemplateClass->GeneralizedClasses.Add(ArgumentGroup,NativeClass);
            GenerializeClass(NativeClass,TemplateClass,ArgumentGroup,InContext);
             
            continue;
        }

        if(NativeClass->IsInnerType() || NativeClass->IsDelegate())
        {
            NativeClass->ParentScope =GlobalNamespace;
            NativeClass->IndexInParent = GlobalNamespace->Classes.Num() - 1;
            GlobalNamespace->Classes.Add(NativeClass);
        }
        else
        {
            NativeClass->ParentScope =NativeNamespace;
            NativeClass->ParentScopeNameChain.Add(U"Engine");
            NativeClass->IndexInParent = NativeNamespace->Classes.Num() - 1;
            NativeNamespace->Classes.Add(NativeClass);
        }
        
        
        NativeClass->Name=Type->GetShortName();



        if(Type->IsClassType())
        {
            NativeClass->MarkAsClass();
        }
        else if(Type->IsEnumType())
        {
            NativeClass->MarkAsEnum();
        }
        else if(Type->IsGenericPlaceholderType())
        {
            NativeClass->MarkAsGenericPlaceholder();
        }
        else if(Type->IsScriptInnerType())
        {
            NativeClass->MarkAsInnerType();
        }
        else if(Type->IsFunctionType())
        {
            NativeClass->MarkAsFunctionPointer();
        }
        else if(Type->IsDelegateType())
        {
            NativeClass->MarkAsDelegate();
        }
        else if(Type->IsValueTypeInScript())
        {
            NativeClass->MarkAsStruct();
        }
        else
        {
            assert(false && "unknown type");
        }


        if(Type->BaseType)
        {
            NativeClass->BaseClass=GetNativeTypeIdentifier(Type->BaseType);
        }

        //add native function
        if(Type->Functions)
        {
            TMap<CFunction* ,std::shared_ptr<CFunctionDescription>> NativeFunctionMap;
            for(auto Function : Type->Functions->Functions)
            {
                if(!Function->CanUseInScript())
                {
                    continue;
                }

                if(Function->IsConstructor())
                {
                    //this is a constructor
                    auto ConstructorDescription = 
                        std::make_shared<CConstructorDescription>();

                    ConstructorDescription->ParentClass = NativeClass;
                    ConstructorDescription->ParentScopeNameChain=NativeClass->ParentScopeNameChain;
                    ConstructorDescription->ParentScopeNameChain.Add(NativeClass->Name);
                    //ConstructorDescription->Name=Function->GetName();
                    NativeClass->Constructors.Add(ConstructorDescription);
                    ConstructorDescription->IndexInParent = NativeClass->Constructors.Num() - 1;

                    //parameters
                    for(auto NativeParameterType : Function->GetParameterTypes())
                    {
                        auto ParameterDescription = std::make_shared<CParameterDescription>();
                        ConstructorDescription->Parameters.Add(ParameterDescription);

                        ParameterDescription->ArgumentIndex =  ConstructorDescription->Parameters.Num() ; 
                        ParameterDescription->Name = U"P_" + CString((uint64_t)ParameterDescription->ArgumentIndex);

                        ParameterDescription->Type = SDecoratedTypeDescription();
                        ParameterDescription->Type.BasicType=GetNativeTypeIdentifier(NativeParameterType.BasicType);

                        for(auto& OverrideGenericType: NativeParameterType.OverrideGenericTypes)
                        {
                            ParameterDescription->Type.OverrideGenericClasses.Add(
                                GetNativeTypeIdentifier(OverrideGenericType)
                            );
                        }
                    }

                    //function pointer type
                    {
                        ConstructorDescription->FunctionPointerType= SDecoratedTypeDescription();
                        ConstructorDescription->FunctionPointerType.BasicType
                            =GetNativeTypeIdentifier(Function->GetFunctionType());
                    }

                    continue;

                }


                auto NativeFunction = std::make_shared<CFunctionDescription>();
                NativeFunctionMap.Add(Function,NativeFunction);

                NativeFunction->ParentClass = NativeClass;
                NativeFunction->ParentScopeNameChain=NativeClass->ParentScopeNameChain;
                NativeFunction->ParentScopeNameChain.Add(NativeClass->Name);
                NativeFunction->Name=Function->GetName();
                NativeClass->Functions.Add(NativeFunction);
                NativeFunction->IndexInParent = NativeClass->Functions.Num() - 1;

                NativeFunction->SetVirtual(Function->IsVirtual());
                //return type
                NativeFunction->ReturnType.BasicType=GetNativeTypeIdentifier(Function->GetReturnType().BasicType);
                for(auto& OverrideGenericType:Function->GetReturnType().OverrideGenericTypes)
                {
                    NativeFunction->ReturnType.OverrideGenericClasses.Add(
                        GetNativeTypeIdentifier(OverrideGenericType)
                    );
                }

                //parameters
                for(auto NativeParameterType : Function->GetParameterTypes())
                {
                    auto ParameterDescription = std::make_shared<CParameterDescription>();
                    NativeFunction->Parameters.Add(ParameterDescription);

                    ParameterDescription->ArgumentIndex =  NativeFunction->IsStatic()? NativeFunction->Parameters.Num() - 1 :NativeFunction->Parameters.Num() ; 
                    ParameterDescription->Name = U"P_" + CString((uint64_t)ParameterDescription->ArgumentIndex);

                    ParameterDescription->Type = SDecoratedTypeDescription();
                    ParameterDescription->Type.BasicType=GetNativeTypeIdentifier(NativeParameterType.BasicType);

                    for(auto& OverrideGenericType: NativeParameterType.OverrideGenericTypes)
                    {
                        ParameterDescription->Type.OverrideGenericClasses.Add(
                            GetNativeTypeIdentifier(OverrideGenericType)
                        );
                    }

                }

                //function pointer type
                {
                    NativeFunction->FunctionPointerType= SDecoratedTypeDescription();
                    NativeFunction->FunctionPointerType.BasicType
                        =GetNativeTypeIdentifier(Function->GetFunctionType());

                }

            }

            for(auto& Indexer:Type->Functions->Indexers )
            {
                //find Getter and setter function
                auto GetterFunction = NativeFunctionMap[Indexer.Getter];
                auto SetterFunction = NativeFunctionMap[Indexer.Setter];


                //create indexer property
                auto NativeProperty = std::make_shared<CPropertyDescription>();
                NativeProperty->Name= U"Native_Item";
                NativeProperty->ParentScopeNameChain=NativeClass->ParentScopeNameChain;
                NativeProperty->ParentScopeNameChain.Add(NativeClass->Name);

                NativeProperty->Type= GetterFunction->ReturnType;

                NativeProperty->Getter=GetterFunction;
                NativeProperty->Setter=SetterFunction;
                NativeProperty->IndexerParameters=GetterFunction->Parameters;
                
                NativeClass->Properties.Add(NativeProperty);
                NativeClass->Indexers.Add(NativeProperty);

            }
        }

        if(Type->Properties)
        {
            NativeClass->SubclassNonStaticFieldIndexStart = 0;//incase no field
            for(auto& FieldProperty:  Type->Properties->GetNonStaticFieldProperties())
            {
                auto FieldIndex=FieldProperty->FieldProperty->GetFieldIndex();
                if(!FieldProperty->CanUseInScript())
                {
                    NativeClass->SubclassNonStaticFieldIndexStart=
                        CMathBase::Max(FieldIndex+1,NativeClass->SubclassNonStaticFieldIndexStart);
                    continue;
                }

                auto NativeField= std::make_shared<CGSharpFieldDescription>();
                NativeClass->Fields.Add(NativeField);
                NativeField->ParentClass = NativeClass;
                NativeField->ParentScopeNameChain=NativeClass->ParentScopeNameChain;
                NativeField->ParentScopeNameChain.Add(NativeClass->Name);
                NativeField->Name=FieldProperty->GetName();

                NativeField->FieldIndex=FieldIndex;
                NativeClass->SubclassNonStaticFieldIndexStart=
                    CMathBase::Max(FieldIndex+1,NativeClass->SubclassNonStaticFieldIndexStart);
                assert(FieldProperty->GetType().BasicType && "field property type impossible be null" );

                NativeField->Type = SDecoratedTypeDescription();
                NativeField->Type.BasicType=GetNativeTypeIdentifier(FieldProperty->GetType().BasicType);

                NativeField->Decorator= std::make_shared<CDecoratorDescription>();
            }

            //TODO add native non-field property and static field property

        }

        //add field for enum type
        if(Type->IsEnumType())
        {
            CEnumBase * EnumType= static_cast<CEnumBase*>(Type);

            NativeClass->EnumValueType=SDecoratedTypeDescription();
            NativeClass->EnumValueType.BasicType=GetNativeTypeIdentifier(EnumType->GetValueType());

            //create enum field
            int32_t EnumValueIndex=0;
            for(auto& EnumValueName: EnumType->GetAllNames())
            {
                auto NativeField= std::make_shared<CGSharpFieldDescription>();
                NativeClass->Fields.Add(NativeField);
                NativeField->ParentClass = NativeClass;
                NativeField->ParentScopeNameChain=NativeClass->ParentScopeNameChain;
                NativeField->ParentScopeNameChain.Add(NativeClass->Name);
                NativeField->Name=EnumValueName;

                NativeField->FieldIndex=EnumValueIndex;

                NativeField->Type = NativeClass->EnumValueType;

                NativeField->Decorator= std::make_shared<CDecoratorDescription>();
                NativeField->Decorator->bIsStatic = true;

                EnumValueIndex++;
            }
            
        }

        //add native generic info
        if(Type->IsGenericType())
        {
            uint32_t PlaceholderIndex=0;
            //find place holder class description
            for(auto PlaceholderType: Type->GenericInfo->PlaceholderTypes)
            {
                assert(PlaceholderType->IsGenericPlaceholderType() && "must be generic placeholder type" );
                auto PlaceholderClass =GetNativeTypeIdentifier(PlaceholderType);
                assert(PlaceholderClass && "place holder class must create before template class" );

                PlaceholderClass->GenericPlaceholderIndex=PlaceholderIndex;
                PlaceholderClass->GenericPlaceholderParent
                    =std::weak_ptr<CTypeDescription>(NativeClass);
                NativeClass->GenericPlaceholders.Add(PlaceholderClass);
            
                PlaceholderIndex++;

                PlaceholderClass->bIsListPlaceholder = PlaceholderType->IsListPlaceholderType();
            }
        }
    }
}

bool CSemanticAnalyzer::DetermineBaseClass(std::shared_ptr<CScriptFileContext> InFileContext)
{
    std::stack<std::shared_ptr<CNamespaceDescription>> NamespaceStack;
    NamespaceStack.push(Context->GlobalNamespace);

    std::stack<std::shared_ptr<CTypeDescription>> ClassStack;

    //iteral namespaces, and push sub classes in to ClassStack
    while(!NamespaceStack.empty())
    {
        auto Namespace=NamespaceStack.top();
        NamespaceStack.pop();

        for(auto& SubClass : Namespace->Classes)
        {
            //skip native class and function pointer
            if(SubClass->IsNative() 
            ||  SubClass->IsFunctionPointer()
            )
            {
                continue;
            }

            ClassStack.push(SubClass);
        }

        //push subnamespace into stack
        for(auto& SubNamespace: Namespace->Namespaces)
        {
            NamespaceStack.push(SubNamespace);
        }
    };

    //iteral classes 
    while(!ClassStack.empty())
    {
        auto Class =ClassStack.top();
        ClassStack.pop();

        //push sub classes into stack
        for(auto& SubClass : Class->Classes)
        {
            ClassStack.push(SubClass);
        }

        if(InFileContext!=Class->File)
        {
            continue;
        }

        if(!Class->ClassNode)
        {
            continue;
        }

        assert(!Class->BaseClass);

        //try find base class
        for(auto& ParentName : Class->ClassNode->ParentNames)
        {
            if(Class->ClassNode->ParentNames.Num()>1)
            {
                InFileContext->RaiseError(20003,ParentName,U"multiple inheritance is not allowed now");
                return false;
            }
            
            CString BaseTypeNameString=ParentName->ToString();
            auto BaseClass=Class->FindClassInFile(InFileContext,BaseTypeNameString);
        
            //only allow class/interface as baseclass
            if(!BaseClass ||  !(BaseClass->IsClass() || BaseClass->IsInterface()))
            {
                //raise error
                InFileContext->RaiseError(20004,ParentName,U"is not a interface/class");
            }

            if(BaseClass->IsInterface())
            {
                Class->BaseInterfaces.Add(BaseClass);
            }
            else if(BaseClass->IsClass())
            {
                if(Class->IsStruct())
                {
                    InFileContext->RaiseError(20006,ParentName,U"struct can't have a base class, only interface is allowed");
                    return false;
                }
                
                if(Class->BaseClass)
                {
                    InFileContext->RaiseError(20007,ParentName,U"can't have two parent class");
                    return false;
                }

                Class->BaseClass = BaseClass;
            }
        
        }  

        //set base class is Object if not base class set
        if((Class->IsClass() || Class->IsStruct()) && !Class->BaseClass)
        {
            Class->BaseClass = GetInnerTypeClassDescription(EScriptInnerType::Object);
        }
    }

    return true;
}

 std::shared_ptr<CTypeDescription> CSemanticAnalyzer::CreateClassDescription(
    const TVector<CString> &ParentNameChain
    , TVariant<std::shared_ptr<CTypeDescription>, std::shared_ptr<CNamespaceDescription>> ParentScope
    , std::shared_ptr<CClassNode> InClassNode
    , std::shared_ptr<CScriptFileContext> InFileContext)
{
    //check duplicated class name
    auto InOutParentClasses = ParentScope.IsA<std::shared_ptr<CTypeDescription>>()? ParentScope.Get<std::shared_ptr<CTypeDescription>>()->Classes : ParentScope.Get<std::shared_ptr<CNamespaceDescription>>()->Classes;
    for(auto& AddedClass:InOutParentClasses)
    {
        if(AddedClass->GetSearchName() == InClassNode->Name->ToString())
        {
            CString ErrorMessage=U"duplicated class name detected: " + AddedClass->GetSearchName();
            ErrorMessage += U" First defined in "+ InFileContext->Compiler.lock()->CreatePositionInfo(AddedClass->File,AddedClass->PositionInFile) + U'\n';
            InFileContext->RaiseError(20010,InClassNode->Name,ErrorMessage);
            return nullptr ;
        }
    }

    auto ClassDescription = std::make_shared<CTypeDescription>();

    
    switch(InClassNode->Class->Type)
    {
        case EScriptTokenType::Class:
            ClassDescription->MarkAsClass();
            break;
        case EScriptTokenType::Struct:
            ClassDescription->MarkAsStruct();
            break;
        case EScriptTokenType::Interface:
            ClassDescription->MarkAsInterface();
            break;
        default:
            assert(false && "not implemented class type");
            break;
    }

    CString ClassName = InClassNode->Name->ToString();
    ClassDescription->Name=ClassName;

    if(ParentScope.IsA<std::shared_ptr<CTypeDescription>>())
    {
        auto ParentClass=ParentScope.Get<std::shared_ptr<CTypeDescription>>();
        ParentClass->Classes.Add(ClassDescription);
        ClassDescription->ParentScope = ParentClass;
        ClassDescription->IndexInParent = ParentClass->Classes.Num() - 1;

    }
    else
    {
        auto ParentNamespace=ParentScope.Get<std::shared_ptr<CNamespaceDescription>>();
        ParentNamespace->Classes.Add(ClassDescription);
        ClassDescription->ParentScope =ParentNamespace;
        ClassDescription->IndexInParent = ParentNamespace->Classes.Num() - 1;
    }

    //创建ID
    switch(InClassNode->Class->Type)
    {
        case EScriptTokenType::Class:
        {
            //创建原始类型ID
            ClassDescription->RawClassTypeID = CreateNonGenerailizedTypeID(
                ParentNameChain
                ,ClassName);

            //创建智能指针ID
            ClassDescription->TypeID =CSharedObjectPtrType::CreateID(
                ClassDescription->RawClassTypeID.GetValue());
            break;
        }
        case EScriptTokenType::Struct:
        {
            ClassDescription->TypeID =CreateNonGenerailizedTypeID(
                ParentNameChain
                ,ClassName
            );
            break;
        }
        case EScriptTokenType::Interface:
            assert(false && "interface not implemented");
            break;
        default:
            assert(false && "not implemented class type");
            break;
    }

    
    AddScriptClass(ClassDescription);

    ClassDescription->ClassNode = InClassNode;
    ClassDescription->File = InFileContext;

    //create generic type parameters
    for(auto& GenericPlaceholder : InClassNode->GenericPlaceholders)
    {
        auto GenericPlaceholderDescription = std::make_shared<CTypeDescription>();

        GenericPlaceholderDescription->ParentScope =ClassDescription;

        GenericPlaceholderDescription->GenericPlaceholderParent=std::weak_ptr<CTypeDescription>(ClassDescription);
        GenericPlaceholderDescription->GenericPlaceholderIndex = ClassDescription->GenericPlaceholders.Num();
        ClassDescription->GenericPlaceholders.Add(GenericPlaceholderDescription);
        GenericPlaceholderDescription->ParentScopeNameChain = ClassDescription->ParentScopeNameChain;
        GenericPlaceholderDescription->ParentScopeNameChain.Add(ClassDescription->Name);
        GenericPlaceholderDescription->Name=GenericPlaceholder->ToString();
        GenericPlaceholderDescription->MarkAsGenericPlaceholder();

        GenericPlaceholderDescription->TypeID =CreateNonGenerailizedTypeID(
            GenericPlaceholderDescription->ParentScopeNameChain
            ,GenericPlaceholderDescription->Name
        );


        //AddScriptClass(GenericPlaceholderDescription);
    }

    ClassDescription->ParentScopeNameChain =ParentNameChain;


    ClassDescription->File = InFileContext;
    ClassDescription->PositionInFile = InClassNode->Name->FilePosition;

    TVector<CString> FullNameChain = ParentNameChain;
    FullNameChain.Add(ClassName);

    return ClassDescription;
}

std::shared_ptr<CTypeDescription> CSemanticAnalyzer::CreateDelegateDescription(
        TVariant<std::shared_ptr<CTypeDescription>, std::shared_ptr<CNamespaceDescription>> ParentScope
        ,std::shared_ptr<CDelegateNode> InDelegateNode
        ,std::shared_ptr<CScriptFileContext> InFileContext)
{
    std::shared_ptr<CTypeDescription> DuplicateClass;
    if(ParentScope.IsA<std::shared_ptr<CTypeDescription>>())
    {
        auto ParentClass=ParentScope.Get<std::shared_ptr<CTypeDescription>>();

        //check is delegate name duplicated
        for(auto& ExistClass:ParentClass->Classes)
        {
            if(ExistClass->Name == InDelegateNode->Name->ToString())
            {
                DuplicateClass=ExistClass;
                break;
            }
        }

        if(!DuplicateClass)
        {
            for(auto& UsingClass:ParentClass->UsingClasses)
            {
                if(UsingClass->AliasName == InDelegateNode->Name->ToString())
                {
                    DuplicateClass=UsingClass->Class;
                    break;
                }
            }
        }
    }
    else
    {
        auto ParentNamespace=ParentScope.Get<std::shared_ptr<CNamespaceDescription>>();
        
        //check is delegate name duplicated
        for(auto& ExistClass:ParentNamespace->Classes)
        {
            if(ExistClass->Name == InDelegateNode->Name->ToString())
            {
                DuplicateClass=ExistClass;
                break;
            }
        }

        if(!DuplicateClass)
        {
            for(auto& UsingClass:ParentNamespace->UsingClasses)
            {
                if(UsingClass->AliasName == InDelegateNode->Name->ToString())
                {
                    DuplicateClass=UsingClass->Class;
                    break;
                }
            }
        }
    }

    if(DuplicateClass)
    {
        CString ErrorMessage=U"duplicated delegate name detected: " + DuplicateClass->GetSearchName();
        ErrorMessage += U"First defined in "+ InFileContext->Compiler.lock()->CreatePositionInfo(DuplicateClass->File,DuplicateClass->PositionInFile) + U'\n';
        InFileContext->RaiseError(20011,InDelegateNode->Name,ErrorMessage);
        return nullptr ;
    }

    auto DelegateDescription = std::make_shared<CTypeDescription>();

    DelegateDescription->MarkAsDelegate();

    ScriptClassesInOrder.Add(DelegateDescription);

    DelegateDescription->DelegateNode = InDelegateNode;

    auto GlobalNamespace=  InFileContext->Compiler.lock()->GlobalNamespace;
    DelegateDescription->ParentScope = GlobalNamespace;
    DelegateDescription->IndexInParent= GlobalNamespace->Classes.Num() - 1;
    GlobalNamespace->Classes.Add(DelegateDescription);

    std::shared_ptr<CClassAlias> UsingClass= std::make_shared<CClassAlias>();
    UsingClass->AliasName = InDelegateNode->Name->ToString();
    UsingClass->Class = DelegateDescription;
    UsingClass->AliasPosition.File=InFileContext;
    UsingClass->AliasPosition.PositionInFile=InDelegateNode->Name->FilePosition;

    DelegateDescription->Alias.Add(UsingClass);
    
    if(ParentScope.IsA<std::shared_ptr<CTypeDescription>>())
    {
        auto ParentClass=ParentScope.Get<std::shared_ptr<CTypeDescription>>();
        ParentClass->UsingClasses.Add(UsingClass);
    }
    else
    {
        auto ParentNamespace=ParentScope.Get<std::shared_ptr<CNamespaceDescription>>();
        ParentNamespace->UsingClasses.Add(UsingClass);
    }

    return DelegateDescription;
}
std::shared_ptr<CTypeDescription> CSemanticAnalyzer::CreateEnumDescription(
    const TVector<CString>& ParentNameChain
    ,TVector<std::shared_ptr<CTypeDescription>>& InOutParentEnums
    , std::shared_ptr<CEnumNode> InEnumNode
    ,std::shared_ptr<CScriptFileContext> InFileContext)
{
    for(auto& AddedEnum:InOutParentEnums)
    {
        if(AddedEnum->GetSearchName() == InEnumNode->Name->ToString())
        {
            CString ErrorMessage=U"duplicated enum name detected: " + AddedEnum->GetSearchName();
            ErrorMessage += U"First defined in "+ InFileContext->Compiler.lock()->CreatePositionInfo(AddedEnum->File,AddedEnum->PositionInFile) + U'\n';
            InFileContext->RaiseError(20012,InEnumNode->Name,ErrorMessage);
            return nullptr ;
        }
    }

    auto EnumDescription = std::make_shared<CTypeDescription>();
    EnumDescription->EnumNode = InEnumNode;
    EnumDescription->ParentScopeNameChain =ParentNameChain;
    EnumDescription->Name=InEnumNode->Name->ToString();
    EnumDescription->EnumValueType = Int64TypeDescription;
    EnumDescription->TypeID =CreateNonGenerailizedTypeID(
        ParentNameChain
        ,EnumDescription->Name
    );

    AddScriptClass(EnumDescription);

    InOutParentEnums.Add(EnumDescription);
    EnumDescription->MarkAsEnum();
    EnumDescription->IndexInParent = InOutParentEnums.Num()-1;

    EnumDescription->File = InFileContext;
    EnumDescription->PositionInFile = InEnumNode->Name->FilePosition;

    return EnumDescription;
}


bool CSemanticAnalyzer::CreateClassLevelTypes(std::shared_ptr<CScriptFileContext> InFileContext)
{
    std::stack<std::shared_ptr<CNamespaceDescription>> NamespaceStack;
    NamespaceStack.push(Context->GlobalNamespace);

    std::stack<std::shared_ptr<CTypeDescription>> ClassStack;

    //iteral namespaces, and push sub classes in to ClassStack
    while(!NamespaceStack.empty())
    {
        auto Namespace=NamespaceStack.top();
        NamespaceStack.pop();

        for(auto& SubClass : Namespace->Classes)
        {
            ClassStack.push(SubClass);
        }

        //push subnamespace into stack
        for(auto& SubNamespace: Namespace->Namespaces)
        {
            NamespaceStack.push(SubNamespace);
        }
    };

    //iteral classes
    while(!ClassStack.empty())
    {
        auto Class= ClassStack.top();
        ClassStack.pop();

        //push sub classes into stack
        for(auto& SubClass : Class->Classes)
        {
            ClassStack.push(SubClass);
        }

        if(Class->IsNative())
        {
            continue;
        }
    }

    return true;
}


bool CSemanticAnalyzer::CreateClassMembers(std::shared_ptr<CScriptFileContext> InFileContext)
{
    std::stack<std::shared_ptr<CNamespaceDescription>> NamespaceStack;
    NamespaceStack.push(Context->GlobalNamespace);

    std::stack<std::shared_ptr<CTypeDescription>> ClassStack;

    //iteral namespaces, and push sub classes in to ClassStack
    while(!NamespaceStack.empty())
    {
        auto Namespace=NamespaceStack.top();
        NamespaceStack.pop();

        for(auto& SubClass : Namespace->Classes)
        {
            ClassStack.push(SubClass);
        }

        //push subnamespace into stack
        for(auto& SubNamespace: Namespace->Namespaces)
        {
            NamespaceStack.push(SubNamespace);
        }
    };

    //iteral classes
    while(!ClassStack.empty())
    {
        auto Class= ClassStack.top();
        ClassStack.pop();

        if(Class->IsNative() )
        {
            continue;
        }

        if(Class->IsEnum())
        {
            assert(Class->EnumNode);
            if(Class->EnumNode->File.lock()!=InFileContext)
            {
                continue;
            }

            int64_t EnumLiteralValue=0;
            bool bAutoAssignValue=true;

            for(auto EnumValue: Class->EnumNode->Values)
            {
                auto EnumValueDescription = std::make_shared<CGSharpFieldDescription>();
                EnumValueDescription->ParentClass = Class;
                EnumValueDescription->ParentScopeNameChain =Class ->ParentScopeNameChain;
                EnumValueDescription->ParentScopeNameChain.Add(Class->Name);
                EnumValueDescription->Name=EnumValue->Name->ToString();
                EnumValueDescription->Type=Int64TypeDescription;

                EnumValueDescription->FieldIndex = Class->Fields.Num();
                Class->Fields.Add(EnumValueDescription);

                EnumValueDescription->Decorator=std::make_shared<CDecoratorDescription>();
                EnumValueDescription->Decorator->bIsStatic = true;

                EnumValueDescription->File = InFileContext;
                EnumValueDescription->PositionInFile = EnumValue->Name->FilePosition;
                
                if(EnumValue->Value)
                {
                    EnumValueDescription->ConstInitializer=EnumValue->Value;
                    bAutoAssignValue=false;
                }

                //set const value as early as possible
                if(bAutoAssignValue)
                {
                    CConstantValue ConstantValue(EnumLiteralValue);
                    EnumValueDescription->ConstValue=ConstantValue;
                    EnumLiteralValue++;
                }
            }

            if(!Class->EnumNode->Values.Empty())
            {
                //create a static constructor to initialize field values
                auto StaticConstructorDescription = std::make_shared<CConstructorDescription>();
                StaticConstructorDescription->ParentScopeNameChain = Class->ParentScopeNameChain;
                StaticConstructorDescription->ParentScopeNameChain.Add(Class->Name);
                StaticConstructorDescription->ParentClass=Class;
                StaticConstructorDescription->bIsStatic = true;
                Class->Constructors.Add(StaticConstructorDescription);

                StaticConstructorDescription->File = InFileContext;
                StaticConstructorDescription->PositionInFile = Class->EnumNode->Name->FilePosition;
                
                //Create body 
                auto Body=std::make_shared<CFunctionBodyDescription>();
                StaticConstructorDescription->Body=Body;

            }

            continue;
        }

        if(Class->IsDelegate())
        {
            if(!Class->Constructors.Empty())
            {
                //memeber functions already added when derivation other file
            }
            else
            {
                SGenericTypeArgumentGroup GenerializeDelegateArgs;

                //derivation return type
                auto TypeResult= DerivationTypeNodeWithClass(
                    InFileContext
                    ,Class
                    ,Class->DelegateNode->ReturnType);
                
                if(!TypeResult.IsSucceed())
                {
                    return false;
                }
                if(TypeResult.bIsVar)
                {
                    //delegate return type can't be var
                    InFileContext->RaiseError(20113,Class->DelegateNode->ReturnType->GetFirstToken(),U"delegate return type can't be var");
                    return false;
                }

                auto ReturnType=TypeResult.Type;




                GenerializeDelegateArgs.Arguments.Add(ReturnType);
        
                //derivation parameters
                TVector<SDecoratedTypeDescription> ParameterTypes;
                for(auto& Parameter:Class->DelegateNode->Parameters)
                {
                    auto ParameterTypeResult= DerivationTypeNodeWithClass(
                        InFileContext
                        ,Class
                        ,Parameter->Type);

                    if(!ParameterTypeResult.IsSucceed())
                    {
                        return false;
                    }

                    if(ParameterTypeResult.bIsVar)
                    {
                        //delegate parameter type can't be var
                        InFileContext->RaiseError(20114,Parameter->Type->GetFirstToken(),U"delegate parameter type can't be var");
                        return false;
                    }

                    ParameterTypes.Add(ParameterTypeResult.Type);
                }

                GenerializeDelegateArgs.Arguments.Append(ParameterTypes);

                TVector<STypeID> ParameterTypeIDs;
                for(auto& ParameterType:ParameterTypes)
                {
                    ParameterTypeIDs.Add(ParameterType.BasicType->TypeID);
                }

                auto ID=CScriptDelegateType::CreateID(
                    ReturnType.BasicType->TypeID,ParameterTypeIDs);

                //find delegate type,if found, continue
                std::shared_ptr<CTypeDescription> FoundDelegate;
                {
                    auto GlobalNamespace=  InFileContext->Compiler.lock()->GlobalNamespace;
                    for(auto& ExistClass:GlobalNamespace->Classes)
                    {
                        if(ExistClass->TypeID==Class->TypeID
                        && ExistClass!=Class)
                        {
                            FoundDelegate=ExistClass;
                            break;
                        }
                    }
                }
               
                if(FoundDelegate)
                {
                    for(auto& Alias: Class->Alias)
                    {
                        Alias.lock()->Class=FoundDelegate;
                    }

                    auto GlobalNamespace=  InFileContext->Compiler.lock()->GlobalNamespace;
                    GlobalNamespace->Classes.Remove(Class);

                    ScriptClassesInOrder.Remove(Class);
                    continue;
                }
                
                Class->TypeID=ID;

                ScriptClasses.Add(Class->TypeID,Class);

                GenerializeClass(
                    Class
                    ,GenericDelegateClassDescription
                    ,GenerializeDelegateArgs
                    ,Context
                );
                
                Class->DelegateFunctionPointerType=
                    FindOrCreateFunctionType(
                    ReturnType
                    ,ParameterTypes
                );
            }
            continue;

        }

        if(
        !Class->File  //some script type ,such as FunctionType donot have file
        || Class->File!=InFileContext
        )
        {
            continue;
        }

        //push sub classes into stack
        for(auto& SubClass : Class->Classes)
        {
            ClassStack.push(SubClass);
        }

        TVector<CString> ClassNamePath=Class->ParentScopeNameChain;
        ClassNamePath.Add(Class->Name);

        if(!Class->ClassNode)
        {
            continue;
        }
    
        for(auto& FieldNode : Class->ClassNode->Fields)
        {
            auto FieldDescription = std::make_shared<CGSharpFieldDescription>();
            FieldDescription->ParentClass = Class;
            Class->Fields.Add(FieldDescription);

            bool IsStatic=false;
            if(FieldNode->Decorator)
            {
                IsStatic =FieldNode->Decorator->IsStatic();
            }

            FieldDescription->Decorator = std::make_shared<CDecoratorDescription>();
            FieldDescription->Decorator->bIsStatic = IsStatic;

            FieldDescription->ParentScopeNameChain = ClassNamePath;
            FieldDescription->Name=FieldNode->Name->ToString();

            auto FieldTypeResult= DerivationTypeNodeWithClass(
                InFileContext
                ,Class
                ,FieldNode->Type);
            
            if(!FieldTypeResult.IsSucceed())
            {
                return false;
            }

            if(FieldTypeResult.bIsVar)
            {
                //field type can't be var
                InFileContext->RaiseError(20180,FieldNode->Type->GetFirstToken(),U"field type can't be var");
                return false;
            }

            FieldDescription->Type = FieldTypeResult.Type;
            FieldDescription->File = InFileContext;
            FieldDescription->PositionInFile = FieldNode->Name->FilePosition;

            if(FieldNode->Assignment.HasValue())
            {
                std::shared_ptr<CExpressionNode> Assignment= FieldNode->Assignment.GetValue();
                FieldDescription->NonConstInitializer = Assignment;
            }
        }

        for(auto & Funtion : Class->ClassNode->Functions)
        {
            auto FunctionDescription = std::make_shared<CFunctionDescription>();
            FunctionDescription->ParentClass = Class;
            Class->Functions.Add(FunctionDescription);
            FunctionDescription->IndexInParent = Class->Functions.Num() - 1;

            FunctionDescription->ParentScopeNameChain = ClassNamePath;
            FunctionDescription->Name=Funtion->Name->ToString();

            FunctionDescription->File = InFileContext;
            FunctionDescription->PositionInFile = Funtion->Name->FilePosition;

            if(Funtion->Decorator.HasValue())
            {
                auto DecoratorNode = Funtion->Decorator.GetValue();
                for(auto& Decorator : DecoratorNode->Decorators)
                {
                    for(auto& Decorator : DecoratorNode->Decorators)
                    {
                        switch(Decorator->Type)
                        {
                            case EScriptTokenType::Static:
                                FunctionDescription->SetStatic(true);
                                break;
                            case EScriptTokenType::Override:
                                FunctionDescription->SetOverride(true);
                                break;
                            case EScriptTokenType::New:
                                FunctionDescription->SetNew(true);
                                break;
                            case EScriptTokenType::Virtual:
                                FunctionDescription->SetVirtual(true);
                                break;
                            default:
                                assert(false &&"unimplemented");
                        }
                    }
                }
            }

            auto ReturTypeResult=  DerivationTypeNodeWithClass(
                InFileContext
                ,Class
                ,Funtion->ReturnType);

            if(!ReturTypeResult.IsSucceed())
            {
                return false;
            }

            if(ReturTypeResult.bIsVar)
            {
                //function return type can't be var
                InFileContext->RaiseError(20181,Funtion->ReturnType->GetFirstToken(),U"function return type can't be var");
                return false;
            }

            FunctionDescription->ReturnType = ReturTypeResult.Type;
            
            for(auto& ParameterNode : Funtion->Parameters)
            {
                auto ParameterDescription = std::make_shared<CParameterDescription>();
                FunctionDescription->Parameters.Add(ParameterDescription);

                ParameterDescription->ArgumentIndex= FunctionDescription->Parameters.Num();
                ParameterDescription->Name= ParameterNode->Name->ToString();
                ParameterDescription->File= InFileContext;

                auto ParameterTypeResult= DerivationTypeNodeWithClass(
                    InFileContext
                    ,Class
                    ,ParameterNode->Type);
                
                if(!ParameterTypeResult.IsSucceed())
                {
                    return false;
                }

                if(ParameterTypeResult.bIsVar)
                {
                    //function parameter type can't be var
                    InFileContext->RaiseError(20182,ParameterNode->Type->GetFirstToken(),U"function parameter type can't be var");
                    return false;
                }

                ParameterDescription->Type =ParameterTypeResult.Type;
            }

            TVector<SDecoratedTypeDescription> ParameterTypes;
            for(auto& Parameter:FunctionDescription->Parameters)
            {
                ParameterTypes.Add(Parameter->Type);
            }
            FunctionDescription->FunctionPointerType= FindOrCreateFunctionType(
                FunctionDescription->ReturnType,ParameterTypes);

            if(Funtion->Content.HasValue())
            {
                FunctionDescription->Body = std::make_shared<CFunctionBodyDescription>();
                FunctionDescription->Body.GetValue()->ASTNode =Funtion->Content.GetValue()->Content;
            }
            else
            {
                //this function is just a declaration, no body
                if(Class->IsInterface())
                {
                    InFileContext->RaiseError(20019,Funtion->Name,U"interface can't have function without body");
                    return false;
                }
                else
                {
                    // this function is a declaration, but it's not in a interface, 
                    // so it must be a virtual function
                    assert(false && "unimplemented");
                }
            }
        }

        for(auto & Constructor : Class->ClassNode->Constructors)
        {
            auto ConstructorDescription = std::make_shared<CConstructorDescription>();
            ConstructorDescription->ParentClass = Class;
            Class->Constructors.Add(ConstructorDescription);
            ConstructorDescription->IndexInParent = Class->Constructors.Num() - 1;

            ConstructorDescription->ParentScopeNameChain = ClassNamePath;
            //ConstructorDescription->Name=Class->Name;

            ConstructorDescription->File = InFileContext;
            ConstructorDescription->PositionInFile = Constructor->Name->FilePosition;

            for(auto& ParameterNode : Constructor->Parameters)
            {
                auto ParameterDescription = std::make_shared<CParameterDescription>();
                ConstructorDescription->Parameters.Add(ParameterDescription);

                ParameterDescription->ArgumentIndex= ConstructorDescription->Parameters.Num();
                ParameterDescription->Name= ParameterNode->Name->ToString();
                ParameterDescription->File= InFileContext;

                auto ParameterTypeResult= DerivationTypeNodeWithClass(
                    InFileContext
                    ,Class
                    ,ParameterNode->Type);
                
                if(!ParameterTypeResult.IsSucceed())
                {
                    return false;
                }

                if(ParameterTypeResult.bIsVar)
                {
                    //constructor parameter type can't be var
                    InFileContext->RaiseError(20183,ParameterNode->Type->GetFirstToken(),U"constructor parameter type can't be var");
                    return false;
                }

                ParameterDescription->Type =ParameterTypeResult.Type;
            }

            TVector<SDecoratedTypeDescription> ParameterTypes;
            for(auto& Parameter:ConstructorDescription->Parameters)
            {
                ParameterTypes.Add(Parameter->Type);
            }
            ConstructorDescription->FunctionPointerType= FindOrCreateFunctionType(
                VoidTypeDescription,ParameterTypes);

            if(Constructor->Content.HasValue())
            {
                ConstructorDescription->Body= std::make_shared<CFunctionBodyDescription>();
                ConstructorDescription->Body.GetValue()->ASTNode =Constructor->Content.GetValue()->Content;
            }
            else
            {
                //this is just a declaration, no body
                assert(false && "unimplemented");
            }
        }

        for(auto& Property : Class->ClassNode->Properties)
        {
            auto PropertyDescription = std::make_shared<CPropertyDescription>();
            PropertyDescription->ParentClass = Class;
            Class->Properties.Add(PropertyDescription);
            PropertyDescription->ParentScopeNameChain = ClassNamePath;

            PropertyDescription->File = InFileContext;
            PropertyDescription->PositionInFile = Property->Name->FilePosition;

            auto PropertyTypeResult= DerivationTypeNodeWithClass( 
                        InFileContext
                        ,Class
                        ,Property->Type
                );
            
            if(!PropertyTypeResult.IsSucceed())
            {
                return false;
            }

            if(PropertyTypeResult.bIsVar)
            {
                //property type can't be var
                InFileContext->RaiseError(20184,Property->Type->GetFirstToken(),U"property type can't be var");
                return false;
            }

            PropertyDescription->Type =PropertyTypeResult.Type;

            if(Property->Name->Type==EScriptTokenType::This)
            {
                PropertyDescription->Name=U"Item";
                Class->Indexers.Add(PropertyDescription);
            }
            else
            {
                PropertyDescription->Name=Property->Name->ToString();
            }

            if(Property->Indexer.HasValue())
            {
                auto Indexer= Property->Indexer.GetValue();

                for(auto Parameter:Indexer->Parameters)
                {
                    auto ParameterDescription = std::make_shared<CParameterDescription>();
                    PropertyDescription->IndexerParameters.Add(ParameterDescription);
                    ParameterDescription->ArgumentIndex= PropertyDescription->IndexerParameters.Num();
                    ParameterDescription->Name= Parameter->Name->ToString();
                    ParameterDescription->File= InFileContext;

                    auto ParameterTypeResult= DerivationTypeNodeWithClass( 
                                InFileContext
                                ,Class
                                ,Parameter->Type
                        );
                    
                    if(!ParameterTypeResult.IsSucceed())
                    {
                        return false;
                    }

                    if(ParameterTypeResult.bIsVar)
                    {
                        //indexer parameter type can't be var
                        InFileContext->RaiseError(20185,Parameter->Type->GetFirstToken(),U"indexer parameter type can't be var");
                        return false;
                    }

                    ParameterDescription->Type =ParameterTypeResult.Type;
                }
            }
            
            if(Property->Getter.HasValue())
            {
                //create a function description
                auto GetterDescription = std::make_shared<CFunctionDescription>();
                PropertyDescription->Getter = GetterDescription;
                Class->Functions.Add(GetterDescription);
                GetterDescription->ParentClass = Class;
                GetterDescription->ParentScopeNameChain = ClassNamePath;
                GetterDescription->Name=U"get_"+PropertyDescription->Name;
                GetterDescription->File = InFileContext;
                GetterDescription->PositionInFile = Property->Name->FilePosition;

                GetterDescription->ReturnType = PropertyDescription->Type;
                GetterDescription->Parameters=  PropertyDescription->IndexerParameters;
                
                GetterDescription->FunctionPointerType= FindOrCreateFunctionTypeWithParameter(
                    PropertyDescription->Type
                    ,PropertyDescription->IndexerParameters
                );
                
                GetterDescription->Body = std::make_shared<CFunctionBodyDescription>();

                std::shared_ptr<CSentenceBlockNode> GetterContent;
                auto GetterNode=Property->Getter.GetValue();
                if(GetterNode->Content.HasValue())
                {
                    GetterContent=GetterNode->Content.GetValue();
                }
                else if(GetterNode->LambdaContent.HasValue())
                {
                    GetterContent=GetterNode->LambdaContent.GetValue();
                }
                else
                {
                    InFileContext->RaiseError(20019,GetterNode->GetFirstToken(),U"donot support auto implemented property now");
                    return false;
                }

                GetterDescription->Body.GetValue()->ASTNode =GetterContent;
            }
            
            if(Property->Setter.HasValue())
            {
                //create a setter function
                auto SetterFunctionDescription = std::make_shared<CFunctionDescription>();
                PropertyDescription->Setter = SetterFunctionDescription;
                Class->Functions.Add(SetterFunctionDescription);
                SetterFunctionDescription->ParentClass = Class;
                SetterFunctionDescription->ParentScopeNameChain = ClassNamePath;
                SetterFunctionDescription->Name=U"set_"+PropertyDescription->Name;
                SetterFunctionDescription->File = InFileContext;
                SetterFunctionDescription->PositionInFile = Property->Name->FilePosition;
                
                SetterFunctionDescription->ReturnType = VoidTypeDescription;
                
                //add indexer parameters
                SetterFunctionDescription->Parameters=  PropertyDescription->IndexerParameters;
                
                //add value parameter
                {
                    auto ValueParameterDescription = std::make_shared<CParameterDescription>();
                    SetterFunctionDescription->Parameters.Add(ValueParameterDescription);

                    ValueParameterDescription->ArgumentIndex= SetterFunctionDescription->Parameters.Num(); //first parameter is this pointer
                    ValueParameterDescription->Name = U"value";
                    ValueParameterDescription->Type = PropertyDescription->Type;
                }

                SetterFunctionDescription->FunctionPointerType= FindOrCreateFunctionTypeWithParameter(
                    VoidTypeDescription
                    ,SetterFunctionDescription->Parameters
                );

                SetterFunctionDescription->Body = std::make_shared<CFunctionBodyDescription>();

                std::shared_ptr<CSentenceBlockNode> SetterContent;
                auto SetterNode=Property->Setter.GetValue();
                if(SetterNode->Content.HasValue())
                {
                    SetterContent=SetterNode->Content.GetValue();
                }
                else if(SetterNode->LambdaContent.HasValue())
                {
                    SetterContent=SetterNode->LambdaContent.GetValue();
                }
                else
                {
                    InFileContext->RaiseError(20020,SetterNode->GetFirstToken(),U"donot support auto implemented property now");
                    return false;
                }

                SetterFunctionDescription->Body.GetValue()->ASTNode =SetterContent;
            }

            if(Property->DefaultValue.HasValue())
            {
                assert(false && "unimplemented");
            }
        }

        //auto add a constructor if  no constructor is defined

        bool bHaveNonStaticConstructor=false;
        for(auto Constructor: Class->Constructors)
        {
            if(Constructor->bIsStatic)
            {
                continue;
            }
            bHaveNonStaticConstructor=true;
            break;
        }

        if(!bHaveNonStaticConstructor)
        {
            auto ConstructorDescription = std::make_shared<CConstructorDescription>();
            Class->Constructors.Add(ConstructorDescription);
            
            ConstructorDescription->ParentScopeNameChain =ClassNamePath;
            //ConstructorDescription->Name=Class->Name;
            ConstructorDescription->ParentClass=Class;
            ConstructorDescription->File = InFileContext;
            ConstructorDescription->PositionInFile = Class->ClassNode->Name->FilePosition;

            ConstructorDescription->Body=std::make_shared<CFunctionBodyDescription>();
            ConstructorDescription->bAutoGenerated = true;

            ConstructorDescription->FunctionPointerType= FindOrCreateFunctionType(
                VoidTypeDescription
                ,{}
            );

        }
    
        bool bNeedStaticConstructor=false;
        for(auto Field: Class->Fields)
        {
            if(Field->IsStatic()
            && Field->NonConstInitializer
            )
            {
                bNeedStaticConstructor=true;
                break;
            }
        }

        if(bNeedStaticConstructor)
        {
            //create a static constructor to initialize constant fields
            auto StaticConstructorDescription = std::make_shared<CConstructorDescription>();
            StaticConstructorDescription->ParentScopeNameChain = ClassNamePath;
            StaticConstructorDescription->ParentClass=Class;
            StaticConstructorDescription->bIsStatic = true;
            Class->Constructors.Add(StaticConstructorDescription);

            StaticConstructorDescription->File = InFileContext;
            StaticConstructorDescription->PositionInFile = Class->ClassNode->Name->FilePosition;

            //Create body
            auto Body=std::make_shared<CFunctionBodyDescription>();
            StaticConstructorDescription->Body=Body;
            StaticConstructorDescription->bAutoGenerated = true;

            StaticConstructorDescription->FunctionPointerType= FindOrCreateFunctionType(
                VoidTypeDescription
                ,{}
            );
           
        }

    }

    return true;
}

bool CSemanticAnalyzer::InitConstantFields(std::shared_ptr<CScriptFileContext> InFileContext)
{
    std::stack<std::shared_ptr<CNamespaceDescription>> NamespaceStack;
    NamespaceStack.push(Context->GlobalNamespace);

    std::stack<std::shared_ptr<CTypeDescription>> ClassStack;

    //iteral namespaces, and push sub classes in to ClassStack
    while(!NamespaceStack.empty())
    {
        auto Namespace=NamespaceStack.top();
        NamespaceStack.pop();

        for(auto& SubClass : Namespace->Classes)
        {
            ClassStack.push(SubClass);
        }

        //push subnamespace into stack
        for(auto& SubNamespace: Namespace->Namespaces)
        {
            NamespaceStack.push(SubNamespace);
        }
    };

    //iteral classes
    while(!ClassStack.empty())
    {
        auto Class= ClassStack.top();
        ClassStack.pop();



        if(Class->IsNative() 
        || !Class->File  //some script type ,such as FunctionType donot have file
        || Class->File!=InFileContext
        )
        {
            continue;
        }

        for(auto& Subclass: Class->Classes)
        {
            ClassStack.push(Subclass);
        }
        
        for(auto& Field: Class->Fields)
        {
            if(!Field->ConstInitializer
            )
            {
                continue;
            }
            
            //derivation expression 

            //create a function context
            auto FunctionBody=std::make_shared<CFunctionBodyDescription>();
            auto FunctionContext = std::make_shared<CFunctionContext>(
                FunctionBody
            , VoidTypeDescription
            , TVector<std::shared_ptr<CParameterDescription>>()
            , Field->File
            , Class
            );
            FunctionContext->bIsStatic = true;

            auto Sentence=FunctionContext->NewSentence(
                nullptr
                ,EStatementType::Expression  // assign expression
                );
            auto ExpressionResult= DerivationExpression(
                Sentence->NewExpression(nullptr)
                ,Field->ConstInitializer
            );

            if(!ExpressionResult.IsSucceed())
            {
                return false;
            }

            if(!ExpressionResult.ConstantValue.HasValue())
            {
                //constant field must initilize with constant expression
                InFileContext->RaiseError(20118
                    ,Field->ConstInitializer->GetFirstToken()
                    ,U"constant field must initilize with constant expression");
                return false;
            }

            Field->ConstValue=ExpressionResult.ConstantValue.GetValue();

            
        }

    }

    return true;
}

void CSemanticAnalyzer::GenerializeClass(
    std::shared_ptr<CTypeDescription>& OutGeneralizedClass
    ,std::shared_ptr<CTypeDescription> Template
    , const SGenericTypeArgumentGroup &InArguments
    , std::shared_ptr<CCompilerContext> InCompilerContext
    )
{
    //assert(Template->GenericPlaceholders.Num() == InArguments.Arguments.Num());

    assert(OutGeneralizedClass->TypeID.IsValid() && "must assign ID before invoke this function " );
 
    OutGeneralizedClass->SetClassType(Template->GetClassType());

    if(!OutGeneralizedClass->IsNative())
    {
        ScriptNotFullyGenerializedClass.Add(OutGeneralizedClass);
    }

    OutGeneralizedClass->ParentScopeNameChain = Context->GlobalNamespace->FullNameChain;
    //TODO consider if base class is generic type
    OutGeneralizedClass->BaseClass=Template->BaseClass;

    CString ClassName;

    if(Template->IsDelegate())
    {
        CString ReturnType=InArguments.Arguments[0].BasicType->Name;
        TVector<CString> ParameterTypes;
        for(uint64_t i=1;i<InArguments.Arguments.Num();i++)
        {
            ParameterTypes.Add(InArguments.Arguments[i].BasicType->Name);
        }

        ClassName=CScriptDelegateType::CreateTypeName(
            ReturnType
            ,ParameterTypes
        );
    }
    else if(Template->IsFunctionPointer())
    {
        CString ReturnType=InArguments.Arguments[0].BasicType->Name;
        TVector<CString> ParameterTypes;
        for(uint64_t i=1;i<InArguments.Arguments.Num();i++)
        {
            ParameterTypes.Add(InArguments.Arguments[i].BasicType->Name);
        }

        ClassName=CFunctionType::CreateTypeName(
            ReturnType
            ,ParameterTypes);
    }
    else
    {
        ClassName= Template->Name+ U"<" ;
        for(uint64_t i=0;i<InArguments.Arguments.Num();i++)
        {
            ClassName += InArguments.Arguments[i].ToString();
            if(i!=InArguments.Arguments.Num()-1)
            {
                ClassName += U",";
            }
        }
        ClassName += U">" ;
    }
    OutGeneralizedClass->Name = ClassName;

    if(Template->IsDelegate())
    {

        auto ReturnType = InArguments.Arguments[0];
        
        TVector<SDecoratedTypeDescription> DelegateParameterTypes;
        if( InArguments.Arguments.Num()>1)
        {
            DelegateParameterTypes=InArguments.Arguments.Slice(1,InArguments.Arguments.Num());
        }

        OutGeneralizedClass->DelegateFunctionPointerType= FindOrCreateFunctionType(
            ReturnType
            ,DelegateParameterTypes
        );

    }

    if(Template->IsFunctionPointer())
    {
        SDecoratedTypeDescription Decorated;
        Decorated.BasicType=OutGeneralizedClass;
        FunctionTypeDescriptions.Add(
            InArguments
            ,Decorated);

        OutGeneralizedClass->MarkAsFunctionPointer();  

        OutGeneralizedClass->FunctionPointerReturnType=InArguments.Arguments[0];
        if(InArguments.Arguments.Num()>1)
        {
            OutGeneralizedClass->FunctionPointerParameters=InArguments.Arguments.Slice(1,InArguments.Arguments.Num());          
        }
    }   

    OutGeneralizedClass->File = Template->File;
    OutGeneralizedClass->ParentScope = Template->ParentScope;
    if(!OutGeneralizedClass->ParentScope.Namespace.expired())
    {
        auto ParentNamespace =OutGeneralizedClass->ParentScope.Namespace.lock();
        ParentNamespace->Classes.Add(OutGeneralizedClass);
        OutGeneralizedClass->IndexInParent=ParentNamespace->Classes.Num()-1;

    }
    else if(!OutGeneralizedClass->ParentScope.Type.expired())
    {
        auto ParentClass=OutGeneralizedClass->ParentScope.Type.lock();
        ParentClass->Classes.Add(OutGeneralizedClass);    
        OutGeneralizedClass->IndexInParent= ParentClass->Classes.Num()-1;
    }
    else
    {
        assert(false && "only namespace and class can be parent scope");
    }

    OutGeneralizedClass->GenericClass=Template;
    OutGeneralizedClass->GenericArguments=InArguments;
    OutGeneralizedClass->GenericClass->GeneralizedClasses.Add(
        OutGeneralizedClass->GenericArguments,OutGeneralizedClass);

    //generialize field and function
    for(auto& Field : Template->Fields)
    {
        auto GeneralizedField = std::make_shared<CGSharpFieldDescription>();
        GeneralizedField->ParentClass = OutGeneralizedClass;
        GeneralizedField->ParentScopeNameChain = Field->ParentScopeNameChain;
        GeneralizedField->Name = Field->Name;
        GeneralizedField->File = Field->File;
        GeneralizedField->PositionInFile = Field->PositionInFile;
        GeneralizedField->Decorator = Field->Decorator;

        auto GenerializedTypes=GenerializeType(
            Field->Type
            ,Template->GenericPlaceholders
            ,InArguments
            ,InCompilerContext
            );
        assert(GenerializedTypes.Num()==1);
        GeneralizedField->Type =GenerializedTypes[0];
        GeneralizedField->FieldIndex = Field->FieldIndex;
        GeneralizedField->NonConstInitializer = Field->NonConstInitializer;
        OutGeneralizedClass->Fields.Add(GeneralizedField);
    }
    OutGeneralizedClass->SubclassNonStaticFieldIndexStart=Template->SubclassNonStaticFieldIndexStart;


    for(auto& Constructor: Template->Constructors)
    {
        auto GeneralizedConstructor = std::make_shared<CConstructorDescription>();
        GeneralizedConstructor->ParentScopeNameChain = Constructor->ParentScopeNameChain;
        //GeneralizedConstructor->Name = Constructor->Name;
        GeneralizedConstructor->File = Constructor->File;
        GeneralizedConstructor->PositionInFile = Constructor->PositionInFile;
        GeneralizedConstructor->ParentClass = OutGeneralizedClass;

        if(Constructor->Body.HasValue())
        {
            auto NewBody=std::make_shared<CFunctionBodyDescription>();
            NewBody->ASTNode=Constructor->Body.GetValue()->ASTNode;
            GeneralizedConstructor->Body=NewBody;
        }

        GeneralizedConstructor->FunctionIndex = Constructor->FunctionIndex;
        GeneralizedConstructor->bIsStatic=Constructor->bIsStatic;
        for(auto& Parameter : Constructor->Parameters)
        {
            auto GeneralizedArgTypes=GenerializeType(
                Parameter->Type
                ,Template->GenericPlaceholders
                ,InArguments
                ,InCompilerContext
                );

            for(int32_t i=0;i<GeneralizedArgTypes.Num();i++)
            {
                auto Type=GeneralizedArgTypes[i];
                auto GeneralizedParameter = std::make_shared<CParameterDescription>();
                GeneralizedParameter->Name = Parameter->Name;
                if(i!=0)
                {
                    GeneralizedParameter->Name += U"_" + CString(i);
                }

                GeneralizedParameter->Type = Type;
                GeneralizedConstructor->Parameters.Add(GeneralizedParameter);
            }
        }

        {   
            TVector<SDecoratedTypeDescription> ConstructorParameterTypes;
            for(auto& Parameter : GeneralizedConstructor->Parameters)
            {
                ConstructorParameterTypes.Add(Parameter->Type);
            }

            GeneralizedConstructor->FunctionPointerType= FindOrCreateFunctionType(
                VoidTypeDescription
                ,ConstructorParameterTypes
                );
        }

        OutGeneralizedClass->Constructors.Add(GeneralizedConstructor);
    }

    TMap<std::shared_ptr<CFunctionDescription> /* orignal */
        ,std::shared_ptr<CFunctionDescription> /* generalized */ > GeneralizedFunctionMap;
    for(auto& Function : Template->Functions)
    {
        auto GeneralizedFunction = std::make_shared<CFunctionDescription>();
        GeneralizedFunctionMap.Add(Function,GeneralizedFunction);

        GeneralizedFunction->ParentScopeNameChain = Function->ParentScopeNameChain;
        GeneralizedFunction->Name = Function->Name;

        GeneralizedFunction->File = Function->File;
        GeneralizedFunction->PositionInFile = Function->PositionInFile;
        GeneralizedFunction->SetStatic(Function->IsStatic());
        GeneralizedFunction->SetVirtual(Function->IsVirtual());

        auto ReturnTypes=GenerializeType(
            Function->ReturnType
            ,Template->GenericPlaceholders
            ,InArguments
            ,InCompilerContext
            );
        assert(ReturnTypes.Num()==1);
        GeneralizedFunction->ReturnType = ReturnTypes[0];
        GeneralizedFunction->ParentClass = OutGeneralizedClass;
        GeneralizedFunction->PositionInVirtualTable = Function->PositionInVirtualTable;
        
        if(Function->Body.HasValue())
        {
            auto NewBody=std::make_shared<CFunctionBodyDescription>();
            NewBody->ASTNode=Function->Body.GetValue()->ASTNode;
            GeneralizedFunction->Body=NewBody;
        }
        
        GeneralizedFunction->FunctionIndex = Function->FunctionIndex;
        for(auto& Parameter : Function->Parameters)
        {
            auto GeneralizedArgTypes=GenerializeType(
                Parameter->Type
                ,Template->GenericPlaceholders
                ,InArguments
                ,InCompilerContext
                );

            for(int32_t i=0;i<GeneralizedArgTypes.Num();i++)
            {
                auto Type=GeneralizedArgTypes[i];
                auto GeneralizedParameter = std::make_shared<CParameterDescription>();
                GeneralizedParameter->Name = Parameter->Name;
                if(i!=0)
                {
                    GeneralizedParameter->Name += U"_" + CString(i);
                }

                GeneralizedParameter->Type = Type;
                GeneralizedFunction->Parameters.Add(GeneralizedParameter);
            }
        }
        OutGeneralizedClass->Functions.Add(GeneralizedFunction);
    }

    
    //generialize property
    for(auto& Property: Template-> Properties )
    {
        auto GeneralizedProperty = std::make_shared<CPropertyDescription>();
        OutGeneralizedClass->Properties.Add(GeneralizedProperty);
        GeneralizedProperty->ParentScopeNameChain = Property->ParentScopeNameChain;
        GeneralizedProperty->Name = Property->Name;
        GeneralizedProperty->File = Property->File;
        GeneralizedProperty->PositionInFile = Property->PositionInFile;
        GeneralizedProperty->Decorator = Property->Decorator;
        
        auto GeneralizedPropertyTypes=GenerializeType(
            Property->Type
            ,Template->GenericPlaceholders
            ,InArguments
            ,InCompilerContext
            );
        assert(GeneralizedPropertyTypes.Num()==1);

        GeneralizedProperty->Type = GeneralizedPropertyTypes[0];

        if(Property->Getter)
        {
            GeneralizedProperty->Getter =GeneralizedFunctionMap[Property->Getter];
            GeneralizedProperty->IndexerParameters.Reserve(Property->Getter->Parameters.Num()) ;//= Property->Getter->Parameters;

            //generialize indexer parameter
            for(auto IndexerParameter : Property->Getter->Parameters )
            {
                auto GeneralizedParameterTypes=GenerializeType(
                    IndexerParameter->Type
                    ,Template->GenericPlaceholders
                    ,InArguments
                    ,InCompilerContext
                    );

                for(int32_t i=0;i<GeneralizedParameterTypes.Num();i++)
                {
                    auto Type=GeneralizedParameterTypes[i];
                    auto GeneralizedIndexerParameter = std::make_shared<CParameterDescription>();
                    GeneralizedIndexerParameter->Name = IndexerParameter->Name;
                    if(i!=0)
                    {
                        GeneralizedIndexerParameter->Name += U"_" + CString(i);
                    }

                    GeneralizedIndexerParameter->Type = Type;
                    GeneralizedProperty->IndexerParameters.Add(GeneralizedIndexerParameter);
                }
            }
        }

        if(Property->Setter)
        {
            GeneralizedProperty->Setter =GeneralizedFunctionMap[Property->Setter];
        }

        if(GeneralizedProperty->IndexerParameters.Num()>0)
        {
            //this is a indexeer
            OutGeneralizedClass->Indexers.Add(GeneralizedProperty);
        }
    }



}

TVector<SDecoratedTypeDescription> CSemanticAnalyzer::GenerializeType(
    SDecoratedTypeDescription TemplateType
    , const TVector<std::shared_ptr<CTypeDescription>> &InParameter
    , const SGenericTypeArgumentGroup &InArguments
    , std::shared_ptr<CCompilerContext> InCompilerContext
    )
{

    if(TemplateType.IsSameWith(VoidTypeDescription))
    {
        return {VoidTypeDescription};
    }

    if(TemplateType.BasicType->IsGenericPlaceholder())
    {
        assert(TemplateType.BasicType
                == InParameter[TemplateType.BasicType->GenericPlaceholderIndex]
                && "only same place holder allow to be replaced now");

        int PlaceholderIndex = TemplateType.BasicType->GenericPlaceholderIndex;
        if(TemplateType.BasicType->bIsListPlaceholder)
        {
            if(PlaceholderIndex>=InArguments.Arguments.Num())
            {
                //type list is empty
                return {};
            }
            else
            {
                //use all left arguments
                return InArguments.Arguments.Slice(PlaceholderIndex,InArguments.Arguments.Num());
            }

        }

        //replace generic placeholder with argument
        return {InArguments.Arguments[TemplateType.BasicType->GenericPlaceholderIndex]};

    }


    if(!TemplateType.BasicType->IsGeneric())
    {
        return {TemplateType};
    }

    SGenericTypeArgumentGroup SelfArguments;
    SelfArguments.Arguments.Reserve(TemplateType.BasicType->GenericPlaceholders.Num());

    for(auto& OverrideClass: TemplateType.OverrideGenericClasses)
    {
        if(!OverrideClass->IsGenericPlaceholder())
        {
            SDecoratedTypeDescription OverrideType;
            OverrideType.BasicType=OverrideClass;
            SelfArguments.Arguments.Add(OverrideType);
        }
        if(OverrideClass->bIsListPlaceholder)
        {   
            //use all left arguments
            int PlaceholderIndex = OverrideClass->GenericPlaceholderIndex;
            if(PlaceholderIndex<InArguments.Arguments.Num())
            {
                SelfArguments.Arguments.Append(
                    InArguments.Arguments.Slice(PlaceholderIndex,InArguments.Arguments.Num()));
            }
        }
        else
        {
            SelfArguments.Arguments.Add(InArguments.Arguments[OverrideClass->GenericPlaceholderIndex]);
        }

    }


    //create new type
    SDecoratedTypeDescription Result = SDecoratedTypeDescription();

    //try find a declared generic type
    Result.BasicType=FindOrCreateScriptGenerializedClass(TemplateType.BasicType,SelfArguments,InCompilerContext);
    return {Result};
}

std::shared_ptr<CTypeDescription> CSemanticAnalyzer::FindOrCreateScriptGenerializedClass(std::shared_ptr<CTypeDescription> Template, const SGenericTypeArgumentGroup &InArguments, std::shared_ptr<CCompilerContext> InCompilerContext)
{
    auto Found=
        Template->GeneralizedClasses.Find(InArguments);

    if(Found)
    {
        return *Found;
    }
    else
    {
        auto GeneralizedClass= std::make_shared<CTypeDescription>();

        CString GeneralizedClassName=Template->Name+U"<";
        for(uint64_t i=0;i<InArguments.Arguments.Num();i++)
        {
            GeneralizedClassName+=InArguments.Arguments[i].ToString();
            if(i!=InArguments.Arguments.Num()-1)
            {
                GeneralizedClassName+=U",";
            }
        }
        GeneralizedClassName+=U">";

        //创建类型ID
        TVector<STypeID> InArgumentsTypeID;
        for(auto& Argument:InArguments.Arguments)
        {
            InArgumentsTypeID.Add(Argument.BasicType->TypeID);
        }

        TVector<CString> PlaceholderNames;
        for(auto& Placeholder:Template->GenericPlaceholders)
        {
            PlaceholderNames.Add(Placeholder->Name);
        }

        auto GeneralizedTypeID= STypeID(
            Template->TypeID
            ,InArgumentsTypeID
            ,PlaceholderNames);

        switch (Template->GetClassType())
        {
            case CTypeDescription::EClassType::Class:
            {
                GeneralizedClass->RawClassTypeID=GeneralizedTypeID;
                
                GeneralizedClass->TypeID =CSharedObjectPtrType::CreateID(GeneralizedTypeID);
                break;
            }

            default:
            {
                GeneralizedClass->TypeID =GeneralizedTypeID;
                break;
            }
        }

        AddScriptClass(GeneralizedClass);

        GenerializeClass(
            GeneralizedClass
            ,Template
            ,InArguments
            ,InCompilerContext
            );

        return GeneralizedClass;
    }

}

bool CSemanticAnalyzer::InitVirtualFunctionTable(std::shared_ptr<CNamespaceDescription> InNamespace, std::shared_ptr<CCompilerContext> InCompilerContext)
{
    for(auto& Namespace : InNamespace->Namespaces)
    {
        bool Succeed = InitVirtualFunctionTable(Namespace,InCompilerContext);
        if(!Succeed)
        {
            return false;
        }
    }

    for(auto& Class : InNamespace->Classes)
    {
        bool Succeed = InitVirtualFunctionTable(Class,InCompilerContext);
        if(!Succeed)
        {
            return false;
        }
    }

    return true;

}

bool CSemanticAnalyzer::InitVirtualFunctionTable(std::shared_ptr<CTypeDescription> InClass,std::shared_ptr<CCompilerContext> InCompilerContext)
{
    if(InClass->bVirtualFunctionTableInitialized)
    {
        return true;
    }

    for(auto& Class: InClass->Classes)
    {
        bool Succeed = InitVirtualFunctionTable(Class,InCompilerContext);
        if(!Succeed)
        {
            return false;
        }
    }

    if(InClass->BaseClass)
    {
        if(!InitVirtualFunctionTable(InClass->BaseClass,InCompilerContext))
        {
            return false;
        }
    }

    //1. add all virtual function from base class
    if(InClass->BaseClass)
    {
        InClass->VirtualFunctionTable = InClass->BaseClass->VirtualFunctionTable;
    }

    //2. override virtual function 
    for(auto& Function:InClass->Functions)
    {
        if(Function->IsOverride())
        {   
            uint64_t OverridedFunctionIndex = -1;

            for(uint64_t i = 0;i<InClass->VirtualFunctionTable.size();i++)
            {
                if(HaveSameSignature(Function,InClass->VirtualFunctionTable[i]))
                {
                    OverridedFunctionIndex = i;
                    break;
                }
            }
        
            if(OverridedFunctionIndex==-1)
            {
                Function->File->RaiseError(20020,Function->PositionInFile,U"can't find virtual function to override");
                return false;
            }

            Function->PositionInVirtualTable = OverridedFunctionIndex;
            InClass->VirtualFunctionTable[OverridedFunctionIndex] = Function;
        }
    }

    //3. add all virtual function from this class
    for(auto& Function:InClass->Functions)
    {
        if(Function->IsVirtual())
        {
            if(Function->IsOverride())
            {
                //raise error, can't mark override and virtual at the same time
                Function->File->RaiseError(20021,Function->PositionInFile,U"overrided function can't marked as virtual.");
            }

            Function->PositionInVirtualTable=InClass->VirtualFunctionTable.Num();
            InClass->VirtualFunctionTable.Add(Function);
        }
    }

    InClass->bVirtualFunctionTableInitialized = true;

    return true;
}

bool CSemanticAnalyzer::FillFunctionBody(std::shared_ptr<CScriptFileContext> InFileContext)
{
    std::stack<std::shared_ptr<CNamespaceDescription>> NamespaceStack;
    NamespaceStack.push(Context->GlobalNamespace);

    std::stack<std::shared_ptr<CTypeDescription>> ClassStack;

    //iteral namespaces and push class to stack
    while(!NamespaceStack.empty())
    {
        auto Namespace=NamespaceStack.top();
        NamespaceStack.pop();

        for(auto& SubClass : Namespace->Classes)
        {
            ClassStack.push(SubClass);
        }

        //push subnamespace into stack
        for(auto& SubNamespace: Namespace->Namespaces)
        {
            NamespaceStack.push(SubNamespace);
        }
    };

    //iteral classes
    while(!ClassStack.empty())
    {
        auto Class= ClassStack.top();
        ClassStack.pop();

        if(!Class->ClassNode && !Class->EnumNode)
        {
            continue;
        }

        if(Class->ClassNode
            && Class->ClassNode->File.lock()!=InFileContext
        )
        {
            continue;
            
        }

        if(Class->EnumNode
            && Class->EnumNode->File.lock()!=InFileContext
        )
        {
            continue;
        }

        //skip generic class,because the type T is not determined
        //skip generialized class, because the function body might 
        //create a  new generialized class ,that might forget to derive it
        //for example, if "TVector<MyClass>" exist in function body,
        //will create a new generialized class "TVector<MyClass>"
        //and you add it to Class stack and derive it, this is not a good idea
        //so we just skip it,and derive it later 
        if(Class->IsGeneric()  
        || Class->IsGenerailizedClass())
        {
            continue;
        }

        //push sub classes into stack
        for(auto& SubClass : Class->Classes)
        {
            ClassStack.push(SubClass);
        }


        for(auto Function: Class->Functions)
        {
            auto FunctionContext= std::make_shared<CFunctionContext>(
                Function->Body.GetValue()
                , Function->ReturnType
                , Function->Parameters
                , InFileContext
                , Class
                );
            FunctionContext->bIsStatic= Function->IsStatic();

            if(!FillFunctionBodyWithFunctionContext(FunctionContext))
            {
                return false;
            }                          
        }

        for(auto Constructor: Class->Constructors)
        {
            auto FunctionContext= std::make_shared<CFunctionContext>(
                Constructor->Body.GetValue()
                , VoidTypeDescription
                , Constructor->Parameters
                , InFileContext
                , Class
                );

            if(!FillConstructorBodyWithFunctionContext(Constructor,FunctionContext))
            {
                return false;
            }                          
        }

    }

    //derive generialized class function body
    //when derive a generialized class, 
    //treat the T is a alias of the argument type
    while(!ScriptNotFullyGenerializedClass.Empty())
    {
        auto Class=ScriptNotFullyGenerializedClass.Last();
        ScriptNotFullyGenerializedClass.Pop();

        if(Class->GenericClass->IsNative())
        {
            //native type don't need to derive function body
            continue;
        }

        //create alias
        for(int32_t i=0;i<Class->GenericArguments.Arguments.Num();i++)
        {
            auto Placeholder=Class->GenericClass->GenericPlaceholders[i];
            auto Argument=Class->GenericArguments.Arguments[i];
            
            auto Alias=std::make_shared<CClassAlias>();
            Alias->AliasName=Placeholder->Name;
            Alias->Class=Argument.BasicType;
            Class->UsingClasses.Add(Alias);
        }

        for(auto Function: Class->Functions)
        {
            auto FunctionContext= std::make_shared<CFunctionContext>(
                Function->Body.GetValue()
                , Function->ReturnType
                , Function->Parameters
                , InFileContext
                , Class
                );
            FunctionContext->bIsStatic= Function->IsStatic();

            if(!FillFunctionBodyWithFunctionContext(FunctionContext))
            {
                return false;
            }                          
        }

        for(auto Constructor: Class->Constructors)
        {
            auto FunctionContext= std::make_shared<CFunctionContext>(
                Constructor->Body.GetValue()
                , VoidTypeDescription
                , Constructor->Parameters
                , InFileContext
                , Class
                );

            if(!FillConstructorBodyWithFunctionContext(Constructor,FunctionContext))
            {
                return false;
            }                          
        }
    }


    return true;
}

bool CSemanticAnalyzer::FillFunctionBodyWithFunctionContext(std::shared_ptr<CFunctionContext> InFunction)
{
    if(!InFunction->FunctionBody->ASTNode)
    {
        return true;
    }

    auto BlockResult= DerivationSentenceBlock(InFunction,nullptr,InFunction->FunctionBody->ASTNode);
    if(!BlockResult.bSuccess)
    {
        return false;
    }

    //detect load variable operation before assign
    // if(!CheckLoadVariableBeforeAssign(InFunction,BlockResult.Operations,{}))
    // {
    //     return false;
    // }

    //add operation to function body
    for(auto& Operation : BlockResult.Operations)
    {
        InFunction->FunctionBody->AddOperation(Operation);
    }

    return true;
}

bool CSemanticAnalyzer::FillConstructorBodyWithFunctionContext(std::shared_ptr<CConstructorDescription> InConstructor,std::shared_ptr<CFunctionContext> InFunction)
{
    auto Class= InConstructor->ParentClass.lock();
    if(! Class->IsScriptType())
    {
        //native type don't need to derive
        return true;
    }

    //1. assign filed default value
    for(auto &Field : Class->Fields)
    {
        if(!Field->NonConstInitializer)
        {
            continue;
        }

        if(InConstructor->bIsStatic!=Field->IsStatic())
        {
            continue;
        }

        //create function context
        auto FunctionContext = std::make_shared<CFunctionContext>(
            InConstructor->Body.GetValue()
            , VoidTypeDescription
            , TVector<std::shared_ptr<CParameterDescription>>()
            , Field->File
            , Class
            );
        FunctionContext->bIsStatic = Field->IsStatic();

        auto Sentence=FunctionContext->NewSentence(
            nullptr
            ,EStatementType::Expression  // assign expression
            );


        auto AssignResult=DerivationInitializeFieldExpression(
            Sentence->NewExpression(nullptr)
            ,Field
            ,Field->NonConstInitializer
            ,Field->NonConstInitializer->GetFirstToken()
        );

        if(!AssignResult.IsSucceed())
        {
            return false;
        }

        for(auto& Operation : AssignResult.Operations)
        {
            InConstructor->Body.GetValue()->AddOperation(Operation);
        }
        
    }

    //2. invoke base constructor
    if(Class->IsClass() && Class->BaseClass->IsScriptType())
    {
        //find a base constructor
        std::shared_ptr<CConstructorDescription> BaseConstructor;
        for(auto Constructor: Class->BaseClass->Constructors)
        {
            if(Constructor->Parameters.Num()==0
                && !Constructor->bIsStatic
            )
            {
                BaseConstructor=Constructor;
                break;
            }
        }

        if(!BaseConstructor)
        {
            //no base constructor found
            InConstructor->File->RaiseError(20110,InConstructor->PositionInFile,U"can't find base constructor");
            return false;
        }

        //load This
        auto ThisLoadOperation = std::make_shared<CLoadArgumentOperation>(0);
        InConstructor->Body.GetValue()->AddOperation(ThisLoadOperation);
        
        //invoke base constructor
        auto BaseConstructorCallOperation = std::make_shared<CConstructorCallOperation>(BaseConstructor);
        InConstructor->Body.GetValue()->AddOperation(BaseConstructorCallOperation);

    }

    //3. derive function body
    if(InConstructor->bAutoGenerated)
    {
        //auto generated constructor don't need to derive
        return true;
    }

    return FillFunctionBodyWithFunctionContext(InFunction);
}

//give every sentence node a type
CSemanticAnalyzer::SExpressionDerivationResult 
CSemanticAnalyzer::DerivationExpression(
    std::shared_ptr<CExpressionContext> InContext
    ,std::shared_ptr<CExpressionNode> InExpression)
{

    switch(InExpression->Type)
    {
    case EASTNodeType::Parentheses:
    {
        return DerivationParenthesesExpression(InContext,std::static_pointer_cast<CParenthesesNode>(InExpression));
    }

    case EASTNodeType::PositiveValue:
    {
        return DerivationPositiveExpression(InContext,std::static_pointer_cast<CPositiveNode>(InExpression));
    }

    case EASTNodeType::NegativeValue:
    {
        return DerivationNegativeExpression(InContext,std::static_pointer_cast<CNegativeNode>(InExpression));
    }

    case EASTNodeType :: MonocularOperator:
        {
            return DerivationMonocularExpression(InContext,std::static_pointer_cast<CMonocularOperatorNode>(InExpression));
        }

    case EASTNodeType :: Literal:
        {
            return DerivationLiteralExpression(InContext,std::static_pointer_cast<CLiteralNode>(InExpression));
        }
    
    case EASTNodeType:: MemberAccess:
        {
            auto Result=DerivationMemberAccessExpression(InContext,std::static_pointer_cast<CMemberAccessNode>(InExpression));
            return Result;
        }

    case EASTNodeType :: Identifier:
        {
            return  DerivationIdentifierExpression(InContext,std::static_pointer_cast<CIdentifierNode>(InExpression));
        }

    case EASTNodeType :: BinocularOperator:
        {
            return DerivationBinocularOperatorExpression(InContext,std::static_pointer_cast<CBinocularOperatorNode>(InExpression));
        }
    
    case EASTNodeType :: Assign:
        {
            return DerivationAssignExpression(InContext,std::static_pointer_cast<CAssignNode>(InExpression));
        }

    case EASTNodeType::New:
    {
        return DerivationNewExpression(InContext,std::static_pointer_cast<CNewNode>(InExpression));
    }

    case EASTNodeType::FunctionCall:
    {   
        return DerivationFunctionCallExpression(
            InContext
            ,std::static_pointer_cast<CFunctionCallNode>(InExpression)
            ,false
            );
    }

    case EASTNodeType::Value:
    {
        return DerivationValueExpression(InContext,std::static_pointer_cast<CValueNode>(InExpression));

    }

    case EASTNodeType::QuestionColonOperator:
    {
        assert(false && "unimplemented");
    }

    case EASTNodeType::TypeCast:
    {
        return DerivationTypeCastExpression(InContext,std::static_pointer_cast<CTypeCastNode>(InExpression));
    }

    default :
        assert(false && "unimplemented ASTNodeType");
        return SExpressionDerivationResult::Failed();

    }
}

CSemanticAnalyzer::SSentenceDerivationResult CSemanticAnalyzer::DerivationSentenceBlock(
    std::shared_ptr<CFunctionContext> InFunction
    ,std::shared_ptr<CStatementContext> InParentSentence
    , std::shared_ptr<CSentenceBlockNode> InExpressionBlock)
{
    auto BlockSentence= InFunction->NewSentence(
        InParentSentence
        ,EStatementType::Block
        );

    SSentenceDerivationResult BlockResult;
    BlockResult.bSuccess=true;
    BlockResult.StatementContext=BlockSentence;

    for(uint64_t i=0;i<InExpressionBlock->Sentences.Num();i++)
    {
        if(InExpressionBlock->Sentences[i]->Type==EASTNodeType::Empty)
        {
            continue;
        }

        auto File= InExpressionBlock->Sentences[i]->GetFile();
        auto FileLine=InExpressionBlock->Sentences[i]->GetFirstToken()->FilePosition.LineIndex;
        
        //uint32_t FirstSentenceIndex=InFunction->FunctionBody->GetOperations().Num();
    
        SSentenceDerivationResult SentenceResult=DerivationSentence(
            InFunction
            ,BlockSentence
            ,InExpressionBlock->Sentences[i]);

        if(!SentenceResult.bSuccess)
        {
            return SSentenceDerivationResult::Failed();
        }

        BlockResult.Operations.Append(SentenceResult.Operations);

        if(!SentenceResult.Operations.Empty())
        {
            //set break point position info for debug
            std::shared_ptr<IFrameOperation> FirstOperation= SentenceResult.Operations[0];
            FirstOperation->SetBreakpointInfo(File,FileLine);
        }
    }

    return BlockResult;
}

CSemanticAnalyzer::SSentenceDerivationResult CSemanticAnalyzer::DerivationSentence(
    std::shared_ptr<CFunctionContext> InFunction
    , std::shared_ptr<CStatementContext> InParentSentence
    , std::shared_ptr<CSentenceNode> InContext)
{
    switch(InContext->Type)
    {
        case EASTNodeType::SentenceBlock:
        {
            return DerivationSentenceBlock(InFunction,InParentSentence,std::static_pointer_cast<CSentenceBlockNode>(InContext));
        }

        case EASTNodeType::For:
        {
            return DerivationForStatement(InFunction,InParentSentence,std::static_pointer_cast<CForNode>(InContext));
        }

        case EASTNodeType::Switch:
        {
            return DerivationSwitchStatement(InFunction,InParentSentence,std::static_pointer_cast<CSwitchNode>(InContext));
        }

        case EASTNodeType::While:
        {
            return DerivationWhileStatement(InFunction,InParentSentence,std::static_pointer_cast<CWhileNode>(InContext));
        }

        case EASTNodeType::DoWhile:
        {
            return DerivationDoWhileStatement(InFunction,InParentSentence,std::static_pointer_cast<CDoWhileNode>(InContext));
        }

        case EASTNodeType::If:
        {
            return DerivationIfStatement(InFunction,InParentSentence,std::static_pointer_cast<CIfNode>(InContext));
        }

        case EASTNodeType::ExpressionSentence:
        {
            return DerivationExpressionSentence(InFunction,InParentSentence,std::static_pointer_cast<CExpressionSentence>(InContext));
        }
        
        case EASTNodeType::Return:
        {
            return DerivationReturnStatement(InFunction,InParentSentence,std::static_pointer_cast<CReturnNode>(InContext));
        }

        case EASTNodeType::Break:
        {
            return DerivationBreakStatement(InFunction,InParentSentence,std::static_pointer_cast<CBreakNode>(InContext));
        }

        case EASTNodeType::Continue:
        {
            return DerivationContinueStatement(InFunction,InParentSentence,std::static_pointer_cast<CContinueNode>(InContext));
        }

        case EASTNodeType::VariableDeclaration:
        {
            return DerivationVariableDeclarationNode(InFunction,InParentSentence,std::static_pointer_cast<CVariableDeclarationNode>(InContext));
        }


        default:
            assert(false && "unimplemented");
            return SSentenceDerivationResult::Failed();
    };

    return SSentenceDerivationResult::Failed();
}

CSemanticAnalyzer::SExpressionDerivationResult CSemanticAnalyzer::DerivationLiteralExpression(
        std::shared_ptr<CExpressionContext> InContext
        ,std::shared_ptr<CLiteralNode> InNode)
{
    SExpressionDerivationResult Result;

    if(InNode->Value->Type==EScriptTokenType::Null)
    {
        auto LoadNull = std::make_shared<CSimpleInstructionOperation>(EByteCodeInstructions::LoadNullPtr);
        Result.Type=NullPtrTypeDescription;
        Result.Operations.Add(LoadNull);
        return Result;
    }

    auto Literial=InNode->Value->LiteralValue.GetValue();
    if(Literial.IsA<CString>())
    {
        CConstantValue ConstantValue(Literial.Get<CString>());
        Result.ConstantValue=ConstantValue;
        Result.Type = GetInnerTypeDescription(EScriptInnerType::String);
    }
    else if(Literial.IsA<uint64_t>())
    {
        uint64_t Temp=Literial.Get<uint64_t>();

        if(Temp<=std::numeric_limits<int64_t>::max())
        {
            CConstantValue ConstantValue(static_cast<int64_t>(Temp));
            Result.ConstantValue=ConstantValue;
            Result.Type = GetInnerTypeDescription(EScriptInnerType::Int64);
        }
        else
        {
            CConstantValue ConstantValue(Temp);
            Result.ConstantValue=ConstantValue;
            Result.Type = GetInnerTypeDescription(EScriptInnerType::Uint64);
        }
        
    }
    else if(Literial.IsA<double>())
    {
        CConstantValue ConstantValue(Literial.Get<double>());
        Result.ConstantValue=ConstantValue;
        Result.Type = GetInnerTypeDescription(EScriptInnerType::Double);
    }
    else if(Literial.IsA<bool>())
    {
        CConstantValue ConstantValue(Literial.Get<bool>());
        Result.ConstantValue=ConstantValue;
        Result.Type = GetInnerTypeDescription(EScriptInnerType::Bool);
    }
    else if(Literial.IsA<char32_t>())
    {
        CConstantValue ConstantValue(Literial.Get<char32_t>());
        Result.ConstantValue=ConstantValue;
        Result.Type = GetInnerTypeDescription(EScriptInnerType::Char);
    }
    else
    {
        assert(false && "unimplemented literial type");
        return SExpressionDerivationResult::Failed();
    }

    auto LoadLiterial = std::make_shared<CLoadLiteralOperation>(
        Result.ConstantValue.GetValue()
        ,Result.Type.BasicType);
    Result.Operations.Add(LoadLiterial);

    return Result;
}


CSemanticAnalyzer::SExpressionDerivationResult CSemanticAnalyzer::DerivationIdentifierExpression(std::shared_ptr<CExpressionContext> InContext,std::shared_ptr<CIdentifierNode> InNode)
{
    CString IdentifierName=InNode->Identifier->ToString();
    return DerivationIdentifierExpressionWithName(InContext,IdentifierName,InNode->Identifier);
}

CSemanticAnalyzer::SExpressionDerivationResult CSemanticAnalyzer::DerivationIdentifierExpressionWithName(
    std::shared_ptr<CExpressionContext> InContext
    , const CString &InIdentifierName
    , std::shared_ptr<CScriptToken> InErrorToken)
{
    CSemanticAnalyzer::SExpressionDerivationResult Result;

    //detect is this a local variable
    if(auto Variable=InContext->GetSentence()->FindVariableByName(InIdentifierName))
    {
        //load variable to stack
        auto LoadVariable = std::make_shared<CLoadVariableOperation>(Variable,InErrorToken);
        Result.Operations.Add(LoadVariable);
        Result.Type=Variable->Type;
        return Result;
    }

    //detect is this a parameter
    if(auto Parameter= InContext->GetSentence()->FindParameterByName(InIdentifierName))
    {
        //load parameter to stack
        auto LoadArgument = std::make_shared<CLoadArgumentOperation>(Parameter->ArgumentIndex);
        Result.Operations.Add(LoadArgument);
        Result.Type=Parameter->Type;
        
        return Result;
    }

    //detect is this a field
    if(auto Field=InContext->GetSentence()->FindFieldByName(InIdentifierName))
    {
        if(!Field->Decorator->bIsStatic)
        {
            //load this
            auto ThisLoadOperation = std::make_shared<CLoadArgumentOperation>(0);
            Result.Operations.Add(ThisLoadOperation);
        }
  
        //load field to stack
        auto LoadField = std::make_shared<CLoadFieldOperation>(Field);
        Result.Operations.Add(LoadField);
        Result.Type=Field->Type;
        return Result;
    }

    //detect is this a property
    if(auto Property=InContext->GetSentence()->FindPropertyByName(InIdentifierName))
    {
        //load this
        auto ThisLoadOperation = std::make_shared<CLoadArgumentOperation>(0);
        Result.Operations.Add(ThisLoadOperation);
       
        //load property to stack
        auto GetterFunction= Property->Getter;
        if(!GetterFunction)
        {
            InContext->GetFunction()->FileContext->RaiseError(20023,InErrorToken ,U"property \'"+ InIdentifierName+ U"\' is not readable");
            return SExpressionDerivationResult::Failed();
        }
        auto CallFunction = std::make_shared<CFunctionCallOperation>(GetterFunction);
        Result.Operations.Add(CallFunction);
        Result.Type=Property->Type;
        return Result;
    }

    //detect is this a function
    if(InContext->GetSentence()->IsPosibleFunction(InIdentifierName))
    {
        auto Function= FindFunctionByExpectedTypes(InContext,InContext->GetOwnerClass(),InIdentifierName,InErrorToken);
        if(!Function)
        {
            return SExpressionDerivationResult::Failed();
        }

        //load function owner instance
        //load function require load a object
        //becase Delegate need it
        if(Function->IsStatic())
        {
            auto LoadNull = std::make_shared<CSimpleInstructionOperation>(EByteCodeInstructions::LoadNullObject);
            Result.Operations.Add(LoadNull);
           
        }
        else
        {
            auto ThisLoadOperation = std::make_shared<CLoadArgumentOperation>(0);
            Result.Operations.Add(ThisLoadOperation); 
        }

        //load function to stack
        auto LoadFunction = std::make_shared<CLoadFunctionOperation>(Function);
        Result.Operations.Add(LoadFunction);

        //store function pointer to delegate
        auto DelegateType=FindOrCreateDelegateType(Function->FunctionPointerType);
        auto AnonymouseVaraible=InContext->GetSentence()->OcuppyOrAddAnonymousVariable(DelegateType);
        
        //load delegate address to stack
        auto LoadDelegateAddress = std::make_shared<CLoadVariableAddressOperation>(AnonymouseVaraible);
        Result.Operations.Insert(0,LoadDelegateAddress);

        auto DuplicateOperation = std::make_shared<CSimpleInstructionOperation>(EByteCodeInstructions::Duplicate);
        Result.Operations.Insert(1,DuplicateOperation);

        auto InitDelegate = std::make_shared<CInitValueTypeOperation>(DelegateType.BasicType);
        Result.Operations.Insert(2,InitDelegate);
        
        //Construct delegate
        auto ConstructDelegate = std::make_shared<CConstructorCallOperation>(
            DelegateType.BasicType->GetDelegateConstructorByFunctionPointer());
        Result.Operations.Add(ConstructDelegate);

        //load delegate
        auto LoadDelegate = std::make_shared<CLoadVariableOperation>(AnonymouseVaraible);
        Result.Operations.Add(LoadDelegate);

        Result.Type=DelegateType;
        return Result;
    }
  
    //cant load identifier
    InContext->GetFunction()->FileContext->RaiseError(20022,InErrorToken,U"identifier \'"+ InIdentifierName+ U"\' is not a variable");
    return SExpressionDerivationResult::Failed();
}


CSemanticAnalyzer::SExpressionDerivationResult  CSemanticAnalyzer::DerivationBinocularOperatorExpression(std::shared_ptr<CExpressionContext> InContext,std::shared_ptr<CBinocularOperatorNode> InNode)
{
    auto LeftResult=DerivationExpression(InContext->NewSubExpression(),InNode->LeftOperand);
    if(!LeftResult.IsSucceed())
    {
        return SExpressionDerivationResult::Failed();
    }

    auto RightResult=DerivationExpression(InContext->NewSubExpression(),InNode->RightOperand);
    if(!RightResult.IsSucceed())
    {
        return SExpressionDerivationResult::Failed();
    }

    auto LeftType=LeftResult.Type;
    auto RightType=RightResult.Type;

    SExpressionDerivationResult OperateResult;

    //check if both side number type
    bool bBothInnerType=false;
    bool bBothNumberType=false;
    EScriptInnerType LeftInnerType;
    EScriptInnerType RightInnerType;
    if(    (LeftType.BasicType->IsInnerType()  || LeftType.BasicType->IsEnum())
        && (RightType.BasicType->IsInnerType() || RightType.BasicType->IsEnum())
    )
    {
        bBothInnerType=true;
        if(LeftType.BasicType->IsInnerType())
        {
            LeftInnerType=LeftType.BasicType->InnerType.GetValue();
        }
        else
        {
            LeftInnerType=EScriptInnerType::Int64;
        }
        
        if(RightType.BasicType->IsInnerType())
        {
            RightInnerType=RightType.BasicType->InnerType.GetValue();
        }
        else
        {
            RightInnerType=EScriptInnerType::Int64;
        }
        if(WH::IsNumberType(LeftInnerType) && WH::IsNumberType(RightInnerType))
        {
            bBothNumberType=true;   
        }
    }

    //check if both side string type
    if(bBothInnerType 
        &&LeftInnerType==EScriptInnerType::String
        && RightInnerType==EScriptInnerType::String
    )
    {
        //support string + string and string == string and string != string
 
        switch(InNode->Operator->Type)
        {
            case EScriptTokenType::Plus:
            {
                auto ConcatenateStringOperation = std::make_shared<CSimpleInstructionOperation>(EByteCodeInstructions::Add_String);
                OperateResult.Type=StringTypeDescription;
                OperateResult.Operations.Append(LeftResult.Operations);
                OperateResult.Operations.Append(RightResult.Operations);
                OperateResult.Operations.Add(ConcatenateStringOperation);
                return OperateResult;
            }
            case EScriptTokenType::Equal:
            {
                auto EqualStringOperation = std::make_shared<CSimpleInstructionOperation>(EByteCodeInstructions::Compare_Equal_String);
                OperateResult.Type=BoolTypeDescription;
                OperateResult.Operations.Append(LeftResult.Operations);
                OperateResult.Operations.Append(RightResult.Operations);
                OperateResult.Operations.Add(EqualStringOperation);
                return OperateResult;
            }
            case EScriptTokenType::NotEqual:
            {
                auto NotEqualStringOperation = std::make_shared<CSimpleInstructionOperation>(EByteCodeInstructions::Compare_NotEqual_String);
                OperateResult.Type=BoolTypeDescription;
                OperateResult.Operations.Append(LeftResult.Operations);
                OperateResult.Operations.Append(RightResult.Operations);
                OperateResult.Operations.Add(NotEqualStringOperation);
                return OperateResult;
            }

            default:
            {
                InContext->GetFunction()->FileContext->RaiseError(20025,InNode->Operator,U"operator \'"+ InNode->Operator->ToString()+ U"\' is not supported for string");
                return SExpressionDerivationResult::Failed();
            }
        }
    }

    //address + - * /    >= <= == !=
    if(bBothNumberType)
    {
        EScriptInnerType WiderType=GetWiderNumberType(LeftInnerType,RightInnerType);  
        
        //convert both side to wide type
        OperateResult.Operations.Append(LeftResult.Operations);
        if(LeftInnerType!=WiderType)
        {
            auto ConvertOperation = std::make_shared<CInnerTypeConvertionOperation>(LeftInnerType,WiderType);
            OperateResult.Operations.Add(ConvertOperation);
        }

        OperateResult.Operations.Append(RightResult.Operations);
        if(RightInnerType!=WiderType)
        {
            auto ConvertOperation = std::make_shared<CInnerTypeConvertionOperation>(RightInnerType,WiderType);
            OperateResult.Operations.Add(ConvertOperation);
        }

        CString ErrorMessage;
        auto FindInstructionOrNumber=
            [&ErrorMessage](EScriptTokenType InMonocularOperator
            ,EScriptInnerType InWideType )->EByteCodeInstructions
        {
            switch(InMonocularOperator)
            {
                case EScriptTokenType::Plus:
                {
                    switch(InWideType)
                    {
                        case EScriptInnerType::Int8:
                            return EByteCodeInstructions::Add_i8;
                        case EScriptInnerType::Uint8:
                            return EByteCodeInstructions::Add_u8;
                        case EScriptInnerType::Int16:
                            return EByteCodeInstructions::Add_i16;
                        case EScriptInnerType::Uint16:
                            return EByteCodeInstructions::Add_u16;
                        case EScriptInnerType::Int32:
                            return EByteCodeInstructions::Add_i32;
                        case EScriptInnerType::Uint32:
                            return EByteCodeInstructions::Add_u32;
                        case EScriptInnerType::Int64:
                            return EByteCodeInstructions::Add_i64;
                        case EScriptInnerType::Uint64:
                            return EByteCodeInstructions::Add_u64;
                        case EScriptInnerType::Float:
                            return EByteCodeInstructions::Add_f32;
                        case EScriptInnerType::Double:
                            return EByteCodeInstructions::Add_f64;
                        default:
                            assert(false&& "unimplement");
                    }
                }
                case EScriptTokenType::Minus:
                {
                    switch(InWideType)
                    {
                        case EScriptInnerType::Int8:
                            return EByteCodeInstructions::Sub_i8;
                        case EScriptInnerType::Uint8:
                            return EByteCodeInstructions::Sub_u8;
                        case EScriptInnerType::Int16:
                            return EByteCodeInstructions::Sub_i16;
                        case EScriptInnerType::Uint16:
                            return EByteCodeInstructions::Sub_u16;
                        case EScriptInnerType::Int32:
                            return EByteCodeInstructions::Sub_i32;
                        case EScriptInnerType::Uint32:
                            return EByteCodeInstructions::Sub_u32;
                        case EScriptInnerType::Int64:
                            return EByteCodeInstructions::Sub_i64;
                        case EScriptInnerType::Uint64:
                            return EByteCodeInstructions::Sub_u64;
                        case EScriptInnerType::Float:
                            return EByteCodeInstructions::Sub_f32;
                        case EScriptInnerType::Double:
                            return EByteCodeInstructions::Sub_f64;
                        default:
                            assert(false&& "unimplement");
                    }                    
                }
                case EScriptTokenType::Multiply:
                {
                    switch(InWideType)
                    {
                        case EScriptInnerType::Int8:
                            return EByteCodeInstructions::Multiply_i8;
                        case EScriptInnerType::Uint8:
                            return EByteCodeInstructions::Multiply_u8;
                        case EScriptInnerType::Int16:
                            return EByteCodeInstructions::Multiply_i16;
                        case EScriptInnerType::Uint16:
                            return EByteCodeInstructions::Multiply_u16;
                        case EScriptInnerType::Int32:
                            return EByteCodeInstructions::Multiply_i32;
                        case EScriptInnerType::Uint32:
                            return EByteCodeInstructions::Multiply_u32;
                        case EScriptInnerType::Int64:
                            return EByteCodeInstructions::Multiply_i64;
                        case EScriptInnerType::Uint64:
                            return EByteCodeInstructions::Multiply_u64;
                        case EScriptInnerType::Float:
                            return EByteCodeInstructions::Multiply_f32;
                        case EScriptInnerType::Double:
                            return EByteCodeInstructions::Multiply_f64;
                        default:
                            assert(false&& "unimplement");
                    }                         
                }
                case EScriptTokenType::Divide:
                {
                    switch(InWideType)
                    {
                        case EScriptInnerType::Int8:
                            return EByteCodeInstructions::Divide_i8;
                        case EScriptInnerType::Uint8:
                            return EByteCodeInstructions::Divide_u8;
                        case EScriptInnerType::Int16:
                            return EByteCodeInstructions::Divide_i16;
                        case EScriptInnerType::Uint16:
                            return EByteCodeInstructions::Divide_u16;
                        case EScriptInnerType::Int32:
                            return EByteCodeInstructions::Divide_i32;
                        case EScriptInnerType::Uint32:
                            return EByteCodeInstructions::Divide_u32;
                        case EScriptInnerType::Int64:
                            return EByteCodeInstructions::Divide_i64;
                        case EScriptInnerType::Uint64:
                            return EByteCodeInstructions::Divide_u64;
                        case EScriptInnerType::Float:
                            return EByteCodeInstructions::Divide_f32;
                        case EScriptInnerType::Double:
                            return EByteCodeInstructions::Divide_f64;
                        default:
                            assert(false&& "unimplement");
                    }                          
                }
                
                case EScriptTokenType::Mod:
                {
                    switch(InWideType)
                    {
                        case EScriptInnerType::Int8:
                            return EByteCodeInstructions::Mod_i8;
                        case EScriptInnerType::Uint8:
                            return EByteCodeInstructions::Mod_u8;
                        case EScriptInnerType::Int16:
                            return EByteCodeInstructions::Mod_i16;
                        case EScriptInnerType::Uint16:
                            return EByteCodeInstructions::Mod_u16;
                        case EScriptInnerType::Int32:
                            return EByteCodeInstructions::Mod_i32;
                        case EScriptInnerType::Uint32:
                            return EByteCodeInstructions::Mod_u32;
                        case EScriptInnerType::Int64:
                            return EByteCodeInstructions::Mod_i64;
                        case EScriptInnerType::Uint64:
                            return EByteCodeInstructions::Mod_u64;
                        case EScriptInnerType::Float:
                        case EScriptInnerType::Double:
                            //raise error 
                            {
                                ErrorMessage=U"do not support % between float number";
                                return EByteCodeInstructions::Nop;
                            }
                        default:
                            assert(false&& "unimplement");
                    }                          
                }

                case EScriptTokenType::Greater:
                {
                    switch(InWideType)
                    {
                        case EScriptInnerType::Int8:
                            return EByteCodeInstructions::Compare_Greater_i8;
                        case EScriptInnerType::Uint8:
                            return EByteCodeInstructions::Compare_Greater_u8;
                        case EScriptInnerType::Int16:
                            return EByteCodeInstructions::Compare_Greater_i16;
                        case EScriptInnerType::Uint16:
                            return EByteCodeInstructions::Compare_Greater_u16;
                        case EScriptInnerType::Int32:
                            return EByteCodeInstructions::Compare_Greater_i32;
                        case EScriptInnerType::Uint32:
                            return EByteCodeInstructions::Compare_Greater_u32;
                        case EScriptInnerType::Int64:
                            return EByteCodeInstructions::Compare_Greater_i64;
                        case EScriptInnerType::Uint64:
                            return EByteCodeInstructions::Compare_Greater_u64;
                        case EScriptInnerType::Float:
                            return EByteCodeInstructions::Compare_Greater_f32;
                        case EScriptInnerType::Double:
                            return EByteCodeInstructions::Compare_Greater_f64;
                        default:
                            assert(false&& "unimplement");
                    }
                }
                case EScriptTokenType::GreaterEqual:
                {
                    switch(InWideType)
                    {
                        case EScriptInnerType::Int8:
                            return EByteCodeInstructions::Compare_GreaterEqual_i8;
                        case EScriptInnerType::Uint8:
                            return EByteCodeInstructions::Compare_GreaterEqual_u8;
                        case EScriptInnerType::Int16:
                            return EByteCodeInstructions::Compare_GreaterEqual_i16;
                        case EScriptInnerType::Uint16:
                            return EByteCodeInstructions::Compare_GreaterEqual_u16;
                        case EScriptInnerType::Int32:
                            return EByteCodeInstructions::Compare_GreaterEqual_i32;
                        case EScriptInnerType::Uint32:
                            return EByteCodeInstructions::Compare_GreaterEqual_u32;
                        case EScriptInnerType::Int64:
                            return EByteCodeInstructions::Compare_GreaterEqual_i64;
                        case EScriptInnerType::Uint64:
                            return EByteCodeInstructions::Compare_GreaterEqual_u64;
                        case EScriptInnerType::Float:
                            return EByteCodeInstructions::Compare_GreaterEqual_f32;
                        case EScriptInnerType::Double:
                            return EByteCodeInstructions::Compare_GreaterEqual_f64;
                        default:
                            assert(false&& "unimplement");
                    }
                }
                case EScriptTokenType::Less:
                {
                    switch(InWideType)
                    {
                        case EScriptInnerType::Int8:
                            return EByteCodeInstructions::Compare_Less_i8;
                        case EScriptInnerType::Uint8:
                            return EByteCodeInstructions::Compare_Less_u8;
                        case EScriptInnerType::Int16:
                            return EByteCodeInstructions::Compare_Less_i16;
                        case EScriptInnerType::Uint16:
                            return EByteCodeInstructions::Compare_Less_u16;
                        case EScriptInnerType::Int32:
                            return EByteCodeInstructions::Compare_Less_i32;
                        case EScriptInnerType::Uint32:
                            return EByteCodeInstructions::Compare_Less_u32;
                        case EScriptInnerType::Int64:
                            return EByteCodeInstructions::Compare_Less_i64;
                        case EScriptInnerType::Uint64:
                            return EByteCodeInstructions::Compare_Less_u64;
                        case EScriptInnerType::Float:
                            return EByteCodeInstructions::Compare_Less_f32;
                        case EScriptInnerType::Double:
                            return EByteCodeInstructions::Compare_Less_f64;
                        default:
                            assert(false&& "unimplement");
                    }
                }
                case EScriptTokenType::LessEqual:
                {
                    switch(InWideType)
                    {
                        case EScriptInnerType::Int8:
                            return EByteCodeInstructions::Compare_LessEqual_i8;
                        case EScriptInnerType::Uint8:
                            return EByteCodeInstructions::Compare_LessEqual_u8;
                        case EScriptInnerType::Int16:
                            return EByteCodeInstructions::Compare_LessEqual_i16;
                        case EScriptInnerType::Uint16:
                            return EByteCodeInstructions::Compare_LessEqual_u16;
                        case EScriptInnerType::Int32:
                            return EByteCodeInstructions::Compare_LessEqual_i32;
                        case EScriptInnerType::Uint32:
                            return EByteCodeInstructions::Compare_LessEqual_u32;
                        case EScriptInnerType::Int64:
                            return EByteCodeInstructions::Compare_LessEqual_i64;
                        case EScriptInnerType::Uint64:
                            return EByteCodeInstructions::Compare_LessEqual_u64;
                        case EScriptInnerType::Float:
                            return EByteCodeInstructions::Compare_LessEqual_f32;
                        case EScriptInnerType::Double:
                            return EByteCodeInstructions::Compare_LessEqual_f64;
                        default:
                            assert(false&& "unimplement");
                    }
                }
                case EScriptTokenType::Equal:
                {
                    switch(InWideType)
                    {
                        case EScriptInnerType::Int8:
                            return EByteCodeInstructions::Compare_Equal_i8;
                        case EScriptInnerType::Uint8:
                            return EByteCodeInstructions::Compare_Equal_u8;
                        case EScriptInnerType::Int16:
                            return EByteCodeInstructions::Compare_Equal_i16;
                        case EScriptInnerType::Uint16:
                            return EByteCodeInstructions::Compare_Equal_u16;
                        case EScriptInnerType::Int32:
                            return EByteCodeInstructions::Compare_Equal_i32;
                        case EScriptInnerType::Uint32:
                            return EByteCodeInstructions::Compare_Equal_u32;
                        case EScriptInnerType::Int64:
                            return EByteCodeInstructions::Compare_Equal_i64;
                        case EScriptInnerType::Uint64:
                            return EByteCodeInstructions::Compare_Equal_u64;
                        case EScriptInnerType::Float:
                            return EByteCodeInstructions::Compare_Equal_f32;
                        case EScriptInnerType::Double:
                            return EByteCodeInstructions::Compare_Equal_f64;
                        default:
                            assert(false&& "unimplement");
                    }
                }
                case EScriptTokenType::NotEqual:
                {
                    switch(InWideType)
                    {
                        case EScriptInnerType::Int8:
                            return EByteCodeInstructions::Compare_NotEqual_i8;
                        case EScriptInnerType::Uint8:
                            return EByteCodeInstructions::Compare_NotEqual_u8;
                        case EScriptInnerType::Int16:
                            return EByteCodeInstructions::Compare_NotEqual_i16;
                        case EScriptInnerType::Uint16:
                            return EByteCodeInstructions::Compare_NotEqual_u16;
                        case EScriptInnerType::Int32:
                            return EByteCodeInstructions::Compare_NotEqual_i32;
                        case EScriptInnerType::Uint32:
                            return EByteCodeInstructions::Compare_NotEqual_u32;
                        case EScriptInnerType::Int64:
                            return EByteCodeInstructions::Compare_NotEqual_i64;
                        case EScriptInnerType::Uint64:
                            return EByteCodeInstructions::Compare_NotEqual_u64;
                        case EScriptInnerType::Float:
                            return EByteCodeInstructions::Compare_NotEqual_f32;
                        case EScriptInnerType::Double:
                            return EByteCodeInstructions::Compare_NotEqual_f64;
                        default:
                            assert(false&& "unimplement");
                    }
                }
            
                default:
                {
                    assert(false&& "unimplement");
                    return EByteCodeInstructions::Nop;
                }
            }
        };

        //find a property instruction
        EByteCodeInstructions Instruction=FindInstructionOrNumber(InNode->Operator->Type,WiderType);
        
        if(Instruction==EByteCodeInstructions::Nop)
        {
            InContext->GetFunction()->FileContext->RaiseError(20024,InNode->Operator ,ErrorMessage);
            return  SExpressionDerivationResult::Failed();
        }

        //add operation
        auto Operation = std::make_shared<CSimpleInstructionOperation>(Instruction);
        OperateResult.Operations.Add(Operation);

        // //remove do nothing operation
        // InContext->GetFunction()->FunctionBody->RemoveOperation(AfterLeftOperation);
        // InContext->GetFunction()->FunctionBody->RemoveOperation(AfterRightOperation);

        switch(InNode->Operator->Type)
        {
            case EScriptTokenType::Plus:
            case EScriptTokenType::Minus:
            case EScriptTokenType::Multiply:
            case EScriptTokenType::Divide:
            case EScriptTokenType::Mod:
            {
                OperateResult.Type=GetInnerTypeDescription(WiderType);
                return OperateResult;
                
            }
            
            default:
            {
                OperateResult.Type=BoolTypeDescription;
                return OperateResult;
            }
        };
    }

    //address || && 
    if(bBothInnerType
        && LeftInnerType==EScriptInnerType::Bool
        && RightInnerType==EScriptInnerType::Bool
    )
    {
        if(InNode->Operator->Type== EScriptTokenType::OrOr)
        {
            auto OrOperation = std::make_shared<CSimpleInstructionOperation>(EByteCodeInstructions::Or);
            OperateResult.Type=BoolTypeDescription;
            OperateResult.Operations.Append(LeftResult.Operations);
            OperateResult.Operations.Append(RightResult.Operations);
            OperateResult.Operations.Add(OrOperation);
            return OperateResult;
        }
        else if(InNode->Operator->Type== EScriptTokenType::AndAnd)
        {
            auto AndOperation = std::make_shared<CSimpleInstructionOperation>(EByteCodeInstructions::And);
            OperateResult.Type=BoolTypeDescription;
            OperateResult.Operations.Append(LeftResult.Operations);
            OperateResult.Operations.Append(RightResult.Operations);
            OperateResult.Operations.Add(AndOperation);
            return OperateResult;
        }
    }

    if(
        (LeftType.BasicType->IsClass() 
        || LeftType.BasicType->IsNullObject()
        || LeftType.BasicType->IsNullPtr()
        )
        && 
        (RightType.BasicType->IsClass() 
        || RightType.BasicType->IsNullObject()
        || RightType.BasicType->IsNullPtr()
        )
    )
    {
        //if both side is null, allow == or !=
        if((LeftType.BasicType->IsNullObject() || LeftType.BasicType->IsNullPtr())
            && (RightType.BasicType->IsNullObject() || RightType.BasicType->IsNullPtr())
        )
        {
            //allow null == null or null != null
            switch(InNode->Operator->Type)
            {
                case EScriptTokenType::Equal:
                {
                    auto LoadTrue = std::make_shared<CLoadLiteralOperation>(true,BoolTypeDescription.BasicType);
                    OperateResult.Type=BoolTypeDescription;
                    OperateResult.Operations.Add(LoadTrue);
                    return OperateResult;
                }
                case EScriptTokenType::NotEqual:
                {
                    auto LoadFalse = std::make_shared<CLoadLiteralOperation>(false,BoolTypeDescription.BasicType);
                    OperateResult.Type=BoolTypeDescription;
                    OperateResult.Operations.Add(LoadFalse);
                    return OperateResult;
                }

                default:
                {
                    InContext->GetFunction()->FileContext->RaiseError(20026,InNode->Operator ,U"operator \'"+ InNode->Operator->ToString()+ U"\' is not supported for null");
                    return SExpressionDerivationResult::Failed();
                }
            };
        }

        //allow Object == Object or Object != Object
        switch(InNode->Operator->Type)
        {
            case EScriptTokenType::Equal:
            case EScriptTokenType::NotEqual:
            {
                EByteCodeInstructions Instruction=  InNode->Operator->Type==EScriptTokenType::Equal?
                    EByteCodeInstructions::Compare_Equal_Object
                    :EByteCodeInstructions::Compare_NotEqual_Object;
                auto EqualOperation = std::make_shared<CSimpleInstructionOperation>(Instruction);
                OperateResult.Type=BoolTypeDescription;
                
                //convert nullptr to nullobject
                if(LeftType.BasicType->IsNullPtr())
                {
                    auto LoadNullObject = std::make_shared<CSimpleInstructionOperation>(EByteCodeInstructions::LoadNullObject);
                    OperateResult.Operations.Add(LoadNullObject);
                }
                else
                {
                    OperateResult.Operations.Append(LeftResult.Operations);
                }

                if(RightType.BasicType->IsNullPtr())
                {
                    auto LoadNullObject = std::make_shared<CSimpleInstructionOperation>(EByteCodeInstructions::LoadNullObject);
                    OperateResult.Operations.Add(LoadNullObject);
                }
                else
                {
                    OperateResult.Operations.Append(RightResult.Operations);
                }
                OperateResult.Operations.Add(EqualOperation);
                return OperateResult;
            }

            default:
            {
                InContext->GetFunction()->FileContext->RaiseError(20026,InNode->Operator ,U"operator \'"+ InNode->Operator->ToString()+ U"\' is not supported for class");
                return SExpressionDerivationResult::Failed();
            }
        };

    }

    //not support
    InContext->GetFunction()->FileContext->RaiseError(20027,InNode->Operator ,U"operator \'"+ InNode->Operator->ToString()+ U"\' is not supported for type");
    return SExpressionDerivationResult::Failed();
}

CSemanticAnalyzer::SMemberAccessResult CSemanticAnalyzer::DerivationMemberAccessExpression(
    std::shared_ptr<CExpressionContext> InContext
    , std::shared_ptr<CMemberAccessNode> InNode
    , bool ExceptLastNode 
    )
{
    SMemberAccessResult Result;
    Result.bSuccess=true;

    int64_t LastNodeIndex = InNode->AccessChain.Num() - 1;
    if(ExceptLastNode)
    {
        LastNodeIndex--;
    }

    int64_t ChainIndex=0;

    //check is first token is Literal 
    if(InNode->AccessChain[0]->Type==EASTNodeType::Literal)
    {
        ChainIndex++;

        //1.load literal to stack 
        auto LiteralNode=std::static_pointer_cast<CLiteralNode>(InNode->AccessChain[0]);
        auto LiterialResult=DerivationLiteralExpression(InContext,LiteralNode);
        if(!LiterialResult.IsSucceed())
        {
            return SMemberAccessResult::Failed();
        }

        Result.Operations.Append(LiterialResult.Operations);

        //2.store literal to Anonymous variable
        auto Variable=InContext->GetSentence()->OcuppyOrAddAnonymousVariable(LiterialResult.Type);
        auto StoreOperation = std::make_shared<CStoreVariableOperation>(Variable);
        Result.Operations.Add(StoreOperation);
        
        //3.load Anonymous variable address to stack
        auto LoadAnonymousVariableAddress = std::make_shared<CLoadVariableAddressOperation>(Variable);
        Result.Operations.Add(LoadAnonymousVariableAddress);
        
        Result.ClassLimitation=std::static_pointer_cast<CTypeDescription>(LiterialResult.Type.BasicType);
    }

    for(;ChainIndex<=LastNodeIndex; ChainIndex++)
    {
        auto CurrentNode = InNode->AccessChain[ChainIndex];

        switch(CurrentNode->Type)
        {
            case EASTNodeType::SentenceIndexer:
            {
                if(ChainIndex==0)
                {
                    //indexer cant be first
                    InContext->GetFunction()->FileContext->RaiseError(20030,CurrentNode->GetFirstToken(),U"indexer must be after identifier");
                    return SMemberAccessResult::Failed();
                }

                auto IndexerNode=std::static_pointer_cast<CSentenceIndexerNode>(CurrentNode);
                if(Result.Type.BasicType->Indexers.Empty())
                {
                    InContext->GetFunction()->FileContext->RaiseError(20031,IndexerNode->GetFirstToken(),U"indexer is not defined for type \'" + Result.Type.BasicType->GetSearchName() + U"\'");
                    return SMemberAccessResult::Failed();
                }

                //1.load indexer parameter  
                TVector<SExpressionDerivationResult> IndexerArguments;
                for(auto IndexerArgument : IndexerNode->Indexers)
                {
                    auto IndexerArgumentResult=DerivationExpression(
                        InContext->NewSubExpression(),IndexerArgument);
                    if(!IndexerArgumentResult.IsSucceed())
                    {
                        return SMemberAccessResult::Failed();
                    }
                    IndexerArguments.Add(IndexerArgumentResult);
                }

                //find a property indexer
                std::shared_ptr<CPropertyDescription> PropertyDescription;

                for(auto IndexerProperty : Result.Type.BasicType->Indexers)
                {
                    if(IndexerProperty->IndexerParameters.Num()!= IndexerNode->Indexers.Num())
                    {
                        continue;
                    }

                    bool bIsMatch=true;

                    for(uint32_t ArgumentIndex=0;ArgumentIndex <IndexerNode->Indexers.Num()  ;ArgumentIndex++)
                    {
                        auto IndexerArgumentType=IndexerArguments[ArgumentIndex].Type;

                        //convet to property indexer type
                        auto PropertyIndexerParameter=IndexerProperty->IndexerParameters[ArgumentIndex];
                        if(!IsStaticConvertable(
                            PropertyIndexerParameter->Type
                            ,IndexerArgumentType
                            ))
                        {
                            bIsMatch=false;
                            break;
                        }
                        
                    }

                    if(bIsMatch)
                    {
                        PropertyDescription=IndexerProperty;
                        break;
                    }
                }

                if(!PropertyDescription)
                {
                    InContext->GetFunction()->FileContext->RaiseError(20032,IndexerNode->GetFirstToken(),U"cant find type matched indexer for type \'" + Result.Type.BasicType->GetSearchName() + U"\'");
                    return SMemberAccessResult::Failed();
                }

                //convert indexer parameter
                TVector<SStaticConvertResult> IndexerConvertResults;
                for(uint32_t ArgumentIndex=0;ArgumentIndex <IndexerNode->Indexers.Num()  ;ArgumentIndex++)
                {
                    auto IndexerArgumentType=IndexerArguments[ArgumentIndex].Type;

                    //convet to property indexer type
                    auto PropertyIndexerParameter=PropertyDescription->IndexerParameters[ArgumentIndex];
                    
                    SStaticConvertResult ConvertResult=
                        StaticConvertTo(InContext->GetFunction()
                            ,PropertyIndexerParameter->Type
                            ,IndexerArgumentType
                            ,IndexerNode->GetFirstToken()
                            );
                    
                    assert(ConvertResult.IsSucceed() && "already check with IsStaticConvertable()");

                    IndexerConvertResults.Add(ConvertResult);
                }

                //combine operators

                //1.load indexer parameter
                for(uint32_t ArgumentIndex=0;ArgumentIndex <IndexerNode->Indexers.Num()  ;ArgumentIndex++)
                {
                    Result.Operations.Append(IndexerArguments[ArgumentIndex].Operations);
                    Result.Operations.Append(IndexerConvertResults[ArgumentIndex].Operations);
                }

                //2.load property to stack
                {
                    auto GetterFunction=PropertyDescription->Getter;
                    if(!GetterFunction)
                    {
                        InContext->GetFunction()->FileContext->RaiseError(20033,IndexerNode->GetFirstToken(),U"indexer do not have getter");
                        return SMemberAccessResult::Failed();
                    }

                    auto InvokeGetterFunction=std::make_shared<CFunctionCallOperation>(GetterFunction);

                    //2. load property
                    Result.Operations.Add(InvokeGetterFunction);
                }

                Result.Type=PropertyDescription->Type;
                Result.ClassLimitation=PropertyDescription->Type.BasicType;
            
                continue;
            }

            case EASTNodeType::Identifier:
            {
                std::shared_ptr<CIdentifierNode> CurrentIdentifier=std::static_pointer_cast<CIdentifierNode>(CurrentNode);
                auto IdentifierName=CurrentIdentifier->Identifier->ToString();

                if(Result.ClassLimitation)
                {
                    //search field
                    
                    if(auto FieldDescription=FindFieldByName(Result.ClassLimitation,IdentifierName))
                    {
                        Result.Type=FieldDescription->Type;

                        if(ChainIndex==0 && !FieldDescription->IsStatic())
                        {
                            std::shared_ptr<CLoadArgumentOperation> LoadThis = std::make_shared<CLoadArgumentOperation>(0);
                            Result.Operations.Add(LoadThis);
                        }

                        if(FieldDescription->IsStatic())
                        {
                            //user might load static field from instance,such as : instance.staticField
                            //remove all operationa,
                            //because static field do not need load this
                            Result.Operations.Clear();
                        }

                        //load field to stack
                        //if this is not last node and field is value type, load field address
                        //otherwise, load field value
                        if(ChainIndex!=InNode->AccessChain.Num()-1
                            && FieldDescription->Type.IsValueType())
                        {
                            auto LoadFieldAddress = std::make_shared<CLoadFieldAddressOperation>(FieldDescription);
                            Result.Operations.Add(LoadFieldAddress);
                        }
                        else
                        {
                            auto LoadField = std::make_shared<CLoadFieldOperation>(FieldDescription);
                            Result.Operations.Add(LoadField);
                        }

                        Result.ClassLimitation=FieldDescription->Type.BasicType;

                        continue;
                    }
                    else if(auto PropertyDescription=Result.ClassLimitation->FindProperty(IdentifierName))
                    {
                        Result.Type=PropertyDescription->Type;

                        if(ChainIndex==0)
                        {
                            std::shared_ptr<CLoadArgumentOperation> LoadThis = std::make_shared<CLoadArgumentOperation>(0);
                            Result.Operations.Add(LoadThis);
                        }

                        {
                            //load property to stack
                            auto GetterFunction=PropertyDescription->Getter;
                            if(!GetterFunction)
                            {
                                InContext->GetFunction()->FileContext->RaiseError(20036,CurrentIdentifier->Identifier,U"property do not have getter");
                                return SMemberAccessResult::Failed();
                            }


                            //2. load property
                            auto InvokeGetterFunction=std::make_shared<CFunctionCallOperation>(GetterFunction);
                            Result.Operations.Add(InvokeGetterFunction);

                            //check if is last node
                            if(ChainIndex!=InNode->AccessChain.Num()-1)
                            {
                                //3. store property to Anonymous variable
                                auto TempVariable=InContext->GetSentence()->OcuppyOrAddAnonymousVariable(PropertyDescription->Type);
                                auto StoreOperation = std::make_shared<CStoreVariableOperation>(TempVariable);
                                Result.Operations.Add(StoreOperation);

                                //4. load Anonymous variable address to stack
                                auto LoadAnonymousVariableAddress = std::make_shared<CLoadVariableAddressOperation>(TempVariable);
                                Result.Operations.Add(LoadAnonymousVariableAddress);
                            }

                        }

                        continue;

                    }
                    else
                    {
                        //try find function
                        if(Result.ClassLimitation->IsPosibleFunction(IdentifierName))
                        {
                            auto Function=FindFunctionByExpectedTypes(
                                InContext
                                ,Result.ClassLimitation
                                ,IdentifierName
                                ,CurrentIdentifier->Identifier
                            );

                            if(!Function)
                            {
                                return SMemberAccessResult::Failed();
                            }

                            if(!Result.Type.IsValid() && !Function->IsStatic())
                            {
                                //cant load a non static function without a object instance
                                InContext->GetFunction()->FileContext->RaiseError(20104,CurrentIdentifier->Identifier,
                                    U"cant load a non static function without a object instance");
                                return SMemberAccessResult::Failed();
                            }

                            if(Function->IsStatic())
                            {
                                //remove all operations  before,
                                //because static function do not need load object instance
                                Result.Operations.Clear();
                            }

                            //load a object instance to stack.
                            //because delegate need a object instance,
                            //there always need load a object instance
                            //before LoadFunctionOperation
                            //static function need to load a null object
                            if(Function->IsStatic())
                            {
                                auto LoadNull = std::make_shared<CSimpleInstructionOperation>(EByteCodeInstructions::LoadNullObject);
                                Result.Operations.Add(LoadNull);
                            }                                                    
                            else if(ChainIndex==0)
                            {
                                //add load this operation
                                std::shared_ptr<CLoadArgumentOperation> LoadThis = std::make_shared<CLoadArgumentOperation>(0);
                                Result.Operations.Add(LoadThis);
                            }

                            //add load function operation
                            auto LoadFunctionOperation=std::make_shared<CLoadFunctionOperation>(Function);
                            Result.Operations.Add(LoadFunctionOperation);

                            //convert to delegate
                            auto DelegateType=
                                FindOrCreateDelegateType(
                                    Function->FunctionPointerType
                                );
                            
                            auto AnonymousVariable=InContext->GetSentence()->OcuppyOrAddAnonymousVariable(DelegateType);
                            
                            //load delegate address to stack
                            auto LoadDelegateAddressOperation=std::make_shared<CLoadVariableAddressOperation>(AnonymousVariable);
                            Result.Operations.Insert(0,LoadDelegateAddressOperation);

                            auto DuplicateOperation=std::make_shared<CSimpleInstructionOperation>(EByteCodeInstructions::Duplicate);
                            Result.Operations.Insert(1,DuplicateOperation);

                            auto InitDelegateOperation=std::make_shared<CInitValueTypeOperation>(DelegateType.BasicType);
                            Result.Operations.Insert(2,InitDelegateOperation);

                            //Construct delegate
                            auto ConstructDelegateOperation=std::make_shared<CConstructorCallOperation>(
                                DelegateType.BasicType->GetDelegateConstructorByFunctionPointer());
                            Result.Operations.Add(ConstructDelegateOperation);
                            
                            //load delegate
                            auto LoadDelegateOperation=std::make_shared<CLoadVariableOperation>(AnonymousVariable);
                            Result.Operations.Add(LoadDelegateOperation);

                            Result.Type=DelegateType;

                            continue;
                        }

                        //raise error, undefined idenfitier
                        InContext->GetFunction()->FileContext->RaiseError(20040,CurrentIdentifier->Identifier,U"undefined identifier");
                        return SMemberAccessResult::Failed();
                    }
                }

                if(Result.NamespaceLimitation)
                {
                    auto NewClassLimitation=Result.NamespaceLimitation->FindClass(IdentifierName);

                    if(NewClassLimitation)
                    {
                        Result.ClassLimitation=NewClassLimitation;
                        Result.NamespaceLimitation = nullptr;
                        continue;     
                    }

                    auto NewNamespaceLimitation=Result.NamespaceLimitation->FindNamespace(IdentifierName);
                    if(NewNamespaceLimitation)
                    {
                        Result.NamespaceLimitation=NewNamespaceLimitation;
                        continue;
                    }

                    //raise error, only support class/namespace access now
                    InContext->GetFunction()->FileContext->RaiseError(20041,CurrentIdentifier->Identifier,U"only support class/namespace access now");
                    return SMemberAccessResult::Failed();
                }

                //detect identifier is a local variable
                if(auto VariableDescription=InContext->GetSentence()->FindVariableByName(IdentifierName))
                {
                    Result.Type=VariableDescription->Type;
                    Result.ClassLimitation= VariableDescription->Type.BasicType;

                    if(ChainIndex!=InNode->AccessChain.Num()-1
                        && VariableDescription->Type.IsValueType())
                    {
                        //load variable address to stack
                        auto LoadVariableAddress = std::make_shared<CLoadVariableAddressOperation>(VariableDescription,CurrentIdentifier->Identifier);
                        Result.Operations.Add(LoadVariableAddress);
                    }
                    else
                    {
                        //load variable to stack
                        auto LoadVariable = std::make_shared<CLoadVariableOperation>(VariableDescription,CurrentIdentifier->Identifier);
                        Result.Operations.Add(LoadVariable);
                    }

                    continue;
                }

                //detect identifier is a parameter
                if(auto ParameterDescription=InContext->GetSentence()->FindParameterByName(IdentifierName))
                {
                    Result.Type=ParameterDescription->Type;
                    Result.ClassLimitation= ParameterDescription->Type.BasicType;

                    if(ChainIndex!=InNode->AccessChain.Num()-1
                        && ParameterDescription->Type.IsValueType())
                    {
                        //load variable address to stack
                        auto LoadVariableAddress = std::make_shared<CLoadArgumentAddressOperation>(ParameterDescription->ArgumentIndex);
                        Result.Operations.Add(LoadVariableAddress);
                    }
                    else
                    {
                        //load variable to stack
                        auto LoadVariable = std::make_shared<CLoadArgumentOperation>(ParameterDescription->ArgumentIndex);
                        Result.Operations.Add(LoadVariable);
                    }

                    continue;
                }

                //detect identifier is a field
                if(std::shared_ptr<CGSharpFieldDescription> FieldDescription=
                    InContext->GetSentence()->FindFieldByName(IdentifierName))
                {
                    Result.Type=FieldDescription->Type;
                    Result.ClassLimitation=FieldDescription->Type.BasicType;

                    if(ChainIndex==0 && !FieldDescription->Decorator->bIsStatic)
                    {
                        std::shared_ptr<CLoadArgumentOperation> LoadThis = std::make_shared<CLoadArgumentOperation>(0);
                        Result.Operations.Add(LoadThis);
                    }

                    if(ChainIndex!=InNode->AccessChain.Num()-1
                        && FieldDescription->Type.IsValueType())
                    {
                        //load field address to stack
                        auto LoadFieldAddress = std::make_shared<CLoadFieldAddressOperation>(FieldDescription);
                        Result.Operations.Add(LoadFieldAddress);
                    }
                    else
                    {
                        //load field to stack
                        auto LoadField = std::make_shared<CLoadFieldOperation>(FieldDescription);
                        Result.Operations.Add(LoadField);
                    }

                    continue;

                }

                //detect identifier is a property
                if(std::shared_ptr<CPropertyDescription> PropertyDescription=
                    InContext->GetSentence()->FindPropertyByName(IdentifierName))
                {
                    Result.Type=PropertyDescription->Type;

                    if(ChainIndex==0 && !PropertyDescription->Decorator->bIsStatic)
                    {
                        std::shared_ptr<CLoadArgumentOperation> LoadThis = std::make_shared<CLoadArgumentOperation>(0);
                        Result.Operations.Add(LoadThis);
                    }

                    {
                        //load property to stack
                        auto GetterFunction=PropertyDescription->Getter;
                        if(!GetterFunction)
                        {
                            InContext->GetFunction()->FileContext->RaiseError(20043,CurrentIdentifier->Identifier,U"property do not have getter");
                            return SMemberAccessResult::Failed();
                        }

                        auto FunctionCall=std::make_shared<CFunctionCallOperation>(GetterFunction);
                        Result.Operations.Add(FunctionCall);
                        
                    }

                    continue;

                }

                //detect identifier is a namespace
                if(auto NamespaceDescription=InContext->GetSentence()->FindNamespaceByName(IdentifierName))
                {
                    Result.NamespaceLimitation=NamespaceDescription;
                    continue;
                }

                //detect identifier is a class
                if(auto ClassDescription=InContext->GetSentence()->FindClassByName(IdentifierName))
                {
                    Result.ClassLimitation=ClassDescription;
                    Result.NamespaceLimitation = nullptr;
                    continue;
                }

                //raise error, only support class/namespace access now
                InContext->GetFunction()->FileContext->RaiseError(20045,CurrentIdentifier->Identifier,U"identifier is not defined");
                return SMemberAccessResult::Failed();
                
                break;
            }


            case  EASTNodeType::FunctionCall:
            {
                auto CurrentFunctionCall=std::static_pointer_cast<CFunctionCallNode>(CurrentNode);
                
                auto FunctionCallResult=
                    DerivationFunctionCallExpression(
                    InContext
                    ,CurrentFunctionCall
                    , ChainIndex!=0
                    ,Result.ClassLimitation);
                if(!FunctionCallResult.IsSucceed())
                {
                    //some error happened
                    return SMemberAccessResult::Failed();
                }

                Result.Type = FunctionCallResult.Type;
                Result.Operations.Append(FunctionCallResult.Operations);

                if(Result.Type.IsSameWith(VoidTypeDescription))
                {
                    if(ChainIndex!=InNode->AccessChain.Num()-1)
                    {
                        //raise error, cant access void
                        InContext->GetFunction()->FileContext->RaiseError(20124,CurrentFunctionCall->GetFirstToken(),U"function return void ,cant access void type");
                        return SMemberAccessResult::Failed();
                    }
                    return Result;
                }

                //save the return value to a anonymous variable 
                //if it is not last node and is a value type 
                if(ChainIndex!=InNode->AccessChain.Num()-1
                    && Result.Type.IsValueType()
                )
                {
                    auto Varaible=InContext->GetSentence()->OcuppyOrAddAnonymousVariable(Result.Type);

                    //add store variable operation
                    auto StoreVariable=std::make_shared<CStoreVariableOperation>(Varaible);
                    Result.Operations.Add(StoreVariable);
                   
                    //add load variable operation for next node
                    auto LoadVariable=std::make_shared<CLoadVariableAddressOperation>(Varaible);
                    Result.Operations.Add( LoadVariable);
                }

                auto ReturnClassDescription=std::static_pointer_cast<CTypeDescription>(Result.Type.BasicType);
                Result.ClassLimitation=ReturnClassDescription;

                continue;
            }

            default:
                //raise error, only support identifier/function call access now
                InContext->GetFunction()->FileContext->RaiseError(20048,CurrentNode->GetFirstToken(),U"only support identifier/function call access now");
                return SMemberAccessResult::Failed();
        }
    }

    return Result;
}

CSemanticAnalyzer::SExpressionDerivationResult CSemanticAnalyzer::DerivationFunctionCallExpression(
    std::shared_ptr<CExpressionContext> InContext
    ,std::shared_ptr<CFunctionCallNode > InNode
    ,bool NotLoadThis 
    ,std::shared_ptr<CTypeDescription> InClassDescription
    )
{
    SExpressionDerivationResult FunctionCallResult;

    auto FunctionName = InNode->GetFunctionName();

    std::shared_ptr<CTypeDescription> FunctionClassDescription;
    if(InClassDescription)
    {
        FunctionClassDescription=InClassDescription;
    }
    else
    {
        FunctionClassDescription = InContext->GetFunction()->OwnerClass.lock();
    }

    TVector<std::shared_ptr<CFunctionDescription>> PotentialFunctions;
    TVector<TVector<SDecoratedTypeDescription>> ArgumentTypes;
    TVector<std::shared_ptr<CExpressionContext>> ArgumentContexts;
    {
        auto MatchNameFunctions=FunctionClassDescription->FindFunctions(FunctionName);

        for(auto& Function: MatchNameFunctions)
        {
            if(Function->IsOverride())
            {
                //skip override function
                continue;
            }

            if(Function->Parameters.Num()!=InNode->Arguments.Num())
            {
                continue;
            }

            PotentialFunctions.Add(Function);
            TVector<SDecoratedTypeDescription> FunctionArugmentTypes;
            for(auto& Parameter: Function->Parameters)
            {
                FunctionArugmentTypes.Add(Parameter->Type);
                //ArgumentContexts.Add(InContext->NewSubExpression());
            }
            ArgumentTypes.Add(FunctionArugmentTypes);
        }

        {
            int MaxParameterNum=0; 
            for(auto& Function: MatchNameFunctions)
            {
                if(Function->Parameters.Num()>MaxParameterNum)
                {
                    MaxParameterNum=Function->Parameters.Num();
                }
            }

            for(int i=0;i<MaxParameterNum;i++)
            {
                ArgumentContexts.Add(InContext->NewSubExpression());
            }
        }

        if(PotentialFunctions.Empty())
        {  
            //this is not a member function, try find a delegate
            //check if it is a delegate

            auto IdentifierResult=DerivationIdentifierExpressionWithName(
                InContext
                ,FunctionName
                ,InNode->GetFirstToken()
                );
            if(!IdentifierResult.IsSucceed())
            {
                //raise error, identifier is not a function
                InContext->GetFunction()->FileContext->RaiseError(20199,InNode->GetFirstToken() ,U"\'"+FunctionName+U"\'is not a function");

                return SExpressionDerivationResult::Failed();
            }
            //do not load this,beacuse this might be loaded in 
            //DerivationIdentifierExpressionWithName 
            NotLoadThis=true;

            FunctionCallResult.Operations.Append(IdentifierResult.Operations);

            auto InvokeFunction=IdentifierResult.Type.BasicType->GetDelegateInvokeFunction();

            PotentialFunctions.Add(InvokeFunction);
            TVector<SDecoratedTypeDescription> FunctionArugmentTypes;
            for(auto& Parameter: InvokeFunction->Parameters)
            {
                FunctionArugmentTypes.Add(Parameter->Type);
                ArgumentContexts.Add(InContext->NewSubExpression());
            }
            ArgumentTypes.Add(FunctionArugmentTypes);
        }
    }

    auto FunctionArgumentResult=
        DerivationFunctionArugments(
            ArgumentContexts
            ,ArgumentTypes
            ,InNode->Arguments
            ,InNode->GetFirstToken()
        );
    if(!FunctionArgumentResult.IsSucceed())
    {
        return SExpressionDerivationResult::Failed();
    }

    //add load argument operations
    FunctionCallResult.Operations.Append(FunctionArgumentResult.Operations);
    auto FunctionDescription=PotentialFunctions[FunctionArgumentResult.FunctionIndex];
    
    //load this if it is not static
    if(!NotLoadThis && !FunctionDescription->IsStatic())
    {
        auto LoadThis= std::make_shared<CLoadArgumentOperation>(0);
        FunctionCallResult.Operations.Insert(0,LoadThis);
    }

    bool bIsVirtual =FunctionDescription->IsVirtual()
        || FunctionDescription->IsOverride();
    if(bIsVirtual)
    {
        auto VirtualFunctionCallOperation=std::make_shared<CVirtualFunctionCallOperation>(FunctionDescription);
        FunctionCallResult.Operations.Add(VirtualFunctionCallOperation);
    }
    else
    {
        auto FunctionCallOperation=std::make_shared<CFunctionCallOperation>(FunctionDescription);
        FunctionCallResult.Operations.Add(FunctionCallOperation);
    }

    FunctionCallResult.Type=FunctionDescription->ReturnType;

    return FunctionCallResult;
}

std::shared_ptr<CFunctionDescription> CSemanticAnalyzer::FindFunctionByExpectedTypes(std::shared_ptr<CExpressionContext> InContext, std::shared_ptr<CTypeDescription> InParentClassDescription, const CString &InFunctionName, std::shared_ptr<CScriptToken> InErrorToken)
{
    TVector<SDecoratedTypeDescription> ExpectedFunctionTypes;
    for(auto& ExpectedType : InContext->ExpectedTypes)
    {
        if(ExpectedType.BasicType->IsDelegate())
        {
            ExpectedFunctionTypes.Add(ExpectedType.BasicType->DelegateFunctionPointerType);
        }
    }

    if(ExpectedFunctionTypes.Empty())
    {
        //raise error, only delegate construction need load function
        InContext->GetFunction()->FileContext->RaiseError(20050
            ,InErrorToken 
            ,U"cant convert function type to target type");
        return nullptr;
    }

    //find function
    std::shared_ptr<CFunctionDescription> Function;

    for(auto& ExpectedFunctionType: ExpectedFunctionTypes)
    {
        auto FoundFunction=InParentClassDescription->FindFunctionByNameAndType(
                InFunctionName,ExpectedFunctionType);

        if(!FoundFunction)
        {
            continue;
        }

        //generally, only one function can be found
        //in some special case, more than one function can be found
        //class A
        //{
        //    void Func(int a);
        //    void Func(double a);
        //}
        //class B
        //{
        //    void InvokeDelegate(TDelegate<int> a);
        //    void InvokeDelegate(TDelegate<double> a);
        //    void Test()
        //    {   
        //        //don't know which function to invoke
        //        InvokeDelegate(Func);
        //    }
        //}
        if(Function)
        {
            //raise error,  ambiguous function
            InContext->GetFunction()->FileContext->RaiseError(20199
                ,InErrorToken 
                ,U"ambiguous function \'"+ InFunctionName+ U"\',more than one function matched");

            break;
        }
        Function=FoundFunction;
    }

    if(!Function)
    {
        InContext->GetFunction()->FileContext->RaiseError(20052
            ,InErrorToken
            ,U"can't find function \'"+ InFunctionName+ U"\' that match required type"
            );
        return nullptr;
    }
    return Function;
}

CSemanticAnalyzer::SFunctionArgumentDerivationResult
 CSemanticAnalyzer::DerivationFunctionArugments(
    const TVector<std::shared_ptr<CExpressionContext>> & InArgumentContexts
    ,const TVector<TVector<SDecoratedTypeDescription>>& InArgumentTypes
    ,const TVector<std::shared_ptr<CExpressionNode>> & InArgumentNodes
    ,std::shared_ptr<CScriptToken> InErrorToken
    )
{
    assert(InArgumentTypes.Num()>0&&"atlleast give one function)");

    SFunctionArgumentDerivationResult Result;

    if(InArgumentNodes.Empty())
    {
        //no argument
        assert(InArgumentTypes.Num()==1 && "function have same name and do not have any parameter" );
        Result.FunctionIndex=0;
        return Result;
    }
    
    //set expected expression type
    for(int ArgumentIndex=0;ArgumentIndex<InArgumentNodes.Num();ArgumentIndex++)
    {
        for(int FunctionIndex=0;FunctionIndex<InArgumentTypes.Num();FunctionIndex++)
        {
            assert(InArgumentTypes[FunctionIndex].Num()==InArgumentNodes.Num()&&"argument number not match");
            InArgumentContexts[ArgumentIndex]->ExpectedTypes
                .Add(InArgumentTypes[FunctionIndex][ArgumentIndex]);
        }
    }

    //derivation arguments
    TVector<SExpressionDerivationResult> ArgumentResults;
    for(int ArgumentIndex=0;ArgumentIndex<InArgumentNodes.Num();ArgumentIndex++)
    {
        auto ArgumentResult=DerivationExpression(InArgumentContexts[ArgumentIndex],InArgumentNodes[ArgumentIndex]);
        if(!ArgumentResult.IsSucceed())
        {
            return SFunctionArgumentDerivationResult::Failed();
        }
        ArgumentResults.Add(ArgumentResult);
    }

    //find a function
    {
        //check is all arguments is same type with expected type
        for(int FunctionIndex=0;FunctionIndex<InArgumentTypes.Num();FunctionIndex++)
        {    
            bool bMatch=true;   
            for(int ArgumentIndex=0;ArgumentIndex<InArgumentNodes.Num();ArgumentIndex++)
            {
                if(!InArgumentTypes[FunctionIndex][ArgumentIndex].IsSameWith(ArgumentResults[ArgumentIndex].Type))
                {
                    bMatch=false;
                    break;
                }
            }

            if(!bMatch)
            {
                continue;
            }

            if(Result.FunctionIndex!=-1)
            {
                //raise error, ambiguous call
                InArgumentContexts[FunctionIndex]->GetFunction()->FileContext->
                    RaiseError(20195,InErrorToken,U"ambiguous function. more than one function matched arguments");
                return SFunctionArgumentDerivationResult::Failed();
            }
            
            Result.FunctionIndex=FunctionIndex;
        }
 
        if(Result.FunctionIndex==-1)
        {
            //find a function with static convert
            for(int FunctionIndex=0;FunctionIndex<InArgumentTypes.Num();FunctionIndex++)
            {    
                bool bMatch=true;   
                for(int ArgumentIndex=0;ArgumentIndex<InArgumentNodes.Num();ArgumentIndex++)
                {
                    if(!IsStaticConvertable(InArgumentTypes[FunctionIndex][ArgumentIndex],ArgumentResults[ArgumentIndex].Type))
                    {
                        bMatch=false;
                        break;
                    }
                }

                if(!bMatch)
                {
                    continue;
                }

                if(Result.FunctionIndex!=-1)
                {
                    //raise error, ambiguous call
                    InArgumentContexts[FunctionIndex]->GetFunction()->FileContext->
                        RaiseError(20196,InErrorToken,U"ambiguous function. more than one function matched arguments");
                    return SFunctionArgumentDerivationResult::Failed();
                }
                
                Result.FunctionIndex=FunctionIndex;
            }
        }

    }

    if(Result.FunctionIndex==-1)
    {
        //raise error, cant find a function
        InArgumentContexts[0]->GetFunction()->FileContext->
            RaiseError(20197,InErrorToken,U"cant find a function matched arguments type");
        return SFunctionArgumentDerivationResult::Failed();
    }

    //convert argument type
    TVector<SStaticConvertResult> ConvertResults;
    for(int ArgumentIndex=0;ArgumentIndex<InArgumentNodes.Num();ArgumentIndex++)
    {
        auto ConvertResult=StaticConvertTo(
            InArgumentContexts[ArgumentIndex]->GetFunction()
            ,InArgumentTypes[Result.FunctionIndex][ArgumentIndex]
            ,ArgumentResults[ArgumentIndex].Type
            ,InArgumentNodes[ArgumentIndex]->GetFirstToken()
            );
        
        if(!ConvertResult.IsSucceed())
        {
            return SFunctionArgumentDerivationResult::Failed();
        }

        ConvertResults.Add(ConvertResult);
    }

    //add load argument operation
    for(int ArgumentIndex=0;ArgumentIndex<InArgumentNodes.Num();ArgumentIndex++)
    {
        Result.Operations.Append(ArgumentResults[ArgumentIndex].Operations);
        Result.Operations.Append(ConvertResults[ArgumentIndex].Operations);
    }

    return Result;
}

CSemanticAnalyzer::SExpressionDerivationResult CSemanticAnalyzer::DerivationAssignExpression(
    std::shared_ptr<CExpressionContext> InContext
    ,std::shared_ptr<CAssignNode > InNode)
{

    CSemanticAnalyzer::SExpressionDerivationResult AssignResult;

    bool BothLoadAndStoreLeftSide= InNode->Operator->Type != EScriptTokenType::Assign;

    SLeftSideDescription LeftSideDescription;

    //derivation left side
    if(InNode->LeftOperand->Type==EASTNodeType::Identifier)
    {
        //left side is identifier
        CString IdentifierName;
        {
            auto IdentifierNode=std::static_pointer_cast<CIdentifierNode>(InNode->LeftOperand);
            IdentifierName=IdentifierNode->Identifier->ToString();
        }

        //detect Identifier is a local variable
        if(auto VariableDescription=InContext->GetSentence()->FindVariableByName(IdentifierName))
        {
            //LeftSideType=VariableDescription->Type;
            LeftSideDescription.LeftSideType=VariableDescription->Type;
            {
                //load variable to stack
                auto LoadVariable = std::make_shared<CLoadVariableOperation>(VariableDescription);
                LeftSideDescription.LoadLeftSideOperations.Add(LoadVariable);
            }

            {
                //store variable to stack
                auto StoreVariable = std::make_shared<CStoreVariableOperation>(VariableDescription);
                LeftSideDescription.StoreLeftSideOperations.Add(StoreVariable);
                LeftSideDescription.OnlyStoreLeftSideOperations.Add(StoreVariable);
            }

        }

        //detect Identifier is a parameter
        else if(auto ParameterDescription=InContext->GetSentence()->FindParameterByName(IdentifierName))
        {
            //LeftSideType=ParameterDescription->Type;
            LeftSideDescription.LeftSideType=ParameterDescription->Type;

            {
                //load parameter to stack
                auto LoadParameter = std::make_shared<CLoadArgumentOperation>(ParameterDescription->ArgumentIndex);
                LeftSideDescription.LoadLeftSideOperations.Add(LoadParameter);
            }

            {
                //store parameter to stack
                auto StoreParameter = std::make_shared<CStoreArgumentOperation>(ParameterDescription->ArgumentIndex);
                LeftSideDescription.StoreLeftSideOperations.Add(StoreParameter);
                LeftSideDescription.OnlyStoreLeftSideOperations.Add(StoreParameter);
            }

        }

        //detect Identifier is a field
        else if(auto FieldDescription=InContext->GetSentence()->FindFieldByName(IdentifierName))
        {
            LeftSideDescription.LeftSideType=FieldDescription->Type;

            if(BothLoadAndStoreLeftSide)
            {
                if(!FieldDescription->IsStatic())
                {
                    auto LoadThis= std::make_shared<CLoadArgumentOperation>(0);
                    AssignResult.Operations.Add(LoadThis);

                    //duplicate this
                    auto DuplicateOperation=std::make_shared<CSimpleInstructionOperation>(EByteCodeInstructions::Duplicate);
                    AssignResult.Operations.Add(DuplicateOperation);
                }

                auto LoadField = std::make_shared<CLoadFieldOperation>(FieldDescription);
                LeftSideDescription.LoadLeftSideOperations.Add(LoadField);

                auto StoreField = std::make_shared<CStoreFieldOperation>(FieldDescription);
                LeftSideDescription.StoreLeftSideOperations.Add(StoreField);        

            }
            else
            {
                if(!FieldDescription->IsStatic())
                {
                    auto LoadThis= std::make_shared<CLoadArgumentOperation>(0);
                    AssignResult.Operations.Add(LoadThis);
                }

                //store field to stack
                auto StoreField = std::make_shared<CStoreFieldOperation>(FieldDescription);
                LeftSideDescription.OnlyStoreLeftSideOperations.Add(StoreField);        
            }
        }
        else
        {
            InContext->GetFunction()->FileContext->RaiseError(20055,InNode->LeftOperand->GetFirstToken(),U"identifier \'"+IdentifierName+U"\' is not defined");
            return SExpressionDerivationResult::Failed();
        }
        
    }
    else if(InNode->LeftOperand->Type==EASTNodeType::MemberAccess)
    {
        //load member access chain to stack except last one
        auto MemberAccessNode=std::static_pointer_cast<CMemberAccessNode>(InNode->LeftOperand);
        
        auto MemberAccessResult=DerivationMemberAccessExpression(InContext,MemberAccessNode,true);
        if(!MemberAccessResult.bSuccess)
        {
            //failed to derive member access chain
            return SExpressionDerivationResult::Failed();
        }
        AssignResult.Operations.Append(MemberAccessResult.Operations);
        
        if(MemberAccessResult.Type.IsValid())
        {
            //last node is field or property or indexer
            auto LastNode=MemberAccessNode->AccessChain[MemberAccessNode->AccessChain.Num()-1];

            switch(LastNode->Type)
            {
                case EASTNodeType::SentenceIndexer:
                {
                    //last node is indexer
                    auto IndexerNode=std::static_pointer_cast<CSentenceIndexerNode>(LastNode);
                    if(MemberAccessResult.Type.BasicType->Indexers.Empty())
                    {
                        InContext->GetFunction()->FileContext->RaiseError(20057,LastNode->GetFirstToken(),U"indexer is not defined for type \'" + MemberAccessResult.Type.BasicType->GetSearchName() + U"\'");
                        return SExpressionDerivationResult::Failed();
                    }

                    if(BothLoadAndStoreLeftSide)
                    {
                        //duplicate Indexer owner
                        auto DuplicateOperation=std::make_shared<CSimpleInstructionOperation>(EByteCodeInstructions::Duplicate);
                        AssignResult.Operations.Add(DuplicateOperation);
                    }

                    //derivation indexers
                    TVector<SExpressionDerivationResult> IndexerResults;
                    for(auto IndexerArgument:IndexerNode->Indexers)
                    {
                        auto IndexerResult=DerivationExpression(InContext->NewSubExpression(),IndexerArgument);
                        if(!IndexerResult.IsSucceed())
                        {
                            return SExpressionDerivationResult::Failed();
                        }
                        IndexerResults.Add(IndexerResult);
                    }

                    //find property
                    std::shared_ptr<CPropertyDescription> PropertyDescription;

                    for(auto IndexerProperty : MemberAccessResult.Type.BasicType->Indexers)
                    {
                        if(IndexerProperty->IndexerParameters.Num()!= IndexerNode->Indexers.Num())
                        {
                            continue;
                        }

                        bool bIsMatch=true;

                        for(uint32_t ArgumentIndex=0;ArgumentIndex <IndexerNode->Indexers.Num()  ;ArgumentIndex++)
                        {
                            auto IndexerArgumentType=IndexerResults[ArgumentIndex].Type;

                            //convet to property indexer type
                            auto PropertyIndexerParameter=IndexerProperty->IndexerParameters[ArgumentIndex];
                            if(!IsStaticConvertable(
                                PropertyIndexerParameter->Type
                                ,IndexerArgumentType
                                ))
                            {
                                bIsMatch=false;
                                break;
                            }
                            
                        }

                        if(bIsMatch)
                        {
                            PropertyDescription=IndexerProperty;
                            break;
                        }
                    }

                    if(!PropertyDescription)
                    {
                        InContext->GetFunction()->FileContext->RaiseError(20032,IndexerNode->GetFirstToken(),U"cant find type matched indexer for type \'" + MemberAccessResult.Type.BasicType->GetSearchName() + U"\'");
                        return SExpressionDerivationResult::Failed();
                    }

                    //convert indexer parameter
                    TVector<SStaticConvertResult> IndexerConvertTypeResults;
                    TVector<std::shared_ptr<CVariableDescription>> IndexerParameters;
                    for(uint32_t ArgumentIndex=0;ArgumentIndex <IndexerNode->Indexers.Num()  ;ArgumentIndex++)
                    {
                        auto IndexerArgumentType=IndexerResults[ArgumentIndex].Type;

                         auto PropertyIndexerParameter=PropertyDescription->IndexerParameters[ArgumentIndex];
                         auto ConvertTypeResult=
                            StaticConvertTo(
                                InContext->GetFunction()
                                ,PropertyIndexerParameter->Type
                                ,IndexerArgumentType
                                ,IndexerNode->Indexers[ArgumentIndex]->GetFirstToken()
                                );
                        assert(ConvertTypeResult.IsSucceed()&& "already check with IsStaticConvertable()");
                        IndexerConvertTypeResults.Add(ConvertTypeResult);

                        if(BothLoadAndStoreLeftSide)
                        {
                            //store indexer parameter in to anonymous variable
                            auto AnonymousVariable=InContext->GetSentence()->OcuppyOrAddAnonymousVariable(PropertyIndexerParameter->Type);
                            auto StoreVariable=std::make_shared<CStoreVariableOperation>(AnonymousVariable);
                            IndexerConvertTypeResults[ArgumentIndex].Operations.Add(StoreVariable);

                            IndexerParameters.Add(AnonymousVariable);
                        }
                    }

                    //combine operators
                    for(uint32_t ArgumentIndex=0;ArgumentIndex <IndexerNode->Indexers.Num()  ;ArgumentIndex++)
                    {
                        AssignResult.Operations.Append(IndexerResults[ArgumentIndex].Operations);
                        AssignResult.Operations.Append(IndexerConvertTypeResults[ArgumentIndex].Operations);
                    }

                    //set property
                    auto SetFunction=PropertyDescription->Setter;

                    if(!SetFunction)
                    {
                        InContext->GetFunction()->FileContext->RaiseError(20071,IndexerNode->GetFirstToken(),U"indexer do not have setter");
                        return SExpressionDerivationResult::Failed();
                    }

                    if(BothLoadAndStoreLeftSide)
                    {
                        //load indexer parameter
                        TVector<std::shared_ptr<IFrameOperation>> LoadIndexerParameters;
                        for(auto IndexerParameter:IndexerParameters)
                        {
                            auto LoadVariable=std::make_shared<CLoadVariableOperation>(IndexerParameter);
                            LoadIndexerParameters.Add(LoadVariable);
                        }

                        //invoke set function
                        auto InvokeSetFunction=std::make_shared<CFunctionCallOperation>(SetFunction);
                        LeftSideDescription.StoreLeftSideOperations.Append(LoadIndexerParameters);
                        LeftSideDescription.StoreLeftSideOperations.Add(InvokeSetFunction);

                        //find and invoke get function
                        auto GetFunction=PropertyDescription->Getter;
                        if(!GetFunction)
                        {
                            InContext->GetFunction()->FileContext->RaiseError(200121,IndexerNode->GetFirstToken(),U"indexer do not have getter");
                            return SExpressionDerivationResult::Failed();
                        }

                        auto InvokeGetFunction=std::make_shared<CFunctionCallOperation>(GetFunction);

                        LeftSideDescription.LoadLeftSideOperations.Append(LoadIndexerParameters);
                        LeftSideDescription.LoadLeftSideOperations.Add(InvokeGetFunction);
                    }
                    else
                    {
                        auto InvokeSetFunction=std::make_shared<CFunctionCallOperation>(SetFunction);
                        LeftSideDescription.OnlyStoreLeftSideOperations.Add(InvokeSetFunction);
                    }

                    LeftSideDescription.LeftSideType=PropertyDescription->Type;

                }
                break;

                case EASTNodeType::Identifier:
                {
                    //last node is identifier
                    auto IdentifierNode=std::static_pointer_cast<CIdentifierNode>(LastNode);
                    auto IdentifierName=IdentifierNode->Identifier->ToString();

                    std::shared_ptr<CTypeDescription> ClassDescription=MemberAccessResult.Type.BasicType;
            
                    //search field
                    if(auto FieldDescription=FindFieldByName(ClassDescription,IdentifierName))
                    {
                        if(FieldDescription->IsStatic())
                        {
                            //user might load static field from instance,such as : instance.staticField
                            //remove operation after first operation,
                            //because static field do not need load this
                            AssignResult.Operations.Clear();
                        }

                        LeftSideDescription.LeftSideType=FieldDescription->Type;

                        if(BothLoadAndStoreLeftSide)
                        {
                            if(!FieldDescription->IsStatic())
                            {
                                //duplicate the field owner
                                auto DuplicateOperation=std::make_shared<CSimpleInstructionOperation>(EByteCodeInstructions::Duplicate);
                                AssignResult.Operations.Add(DuplicateOperation);
                            }

                            auto LoadField = std::make_shared<CLoadFieldOperation>(FieldDescription);
                            LeftSideDescription.LoadLeftSideOperations.Add(LoadField);

                            auto StoreField = std::make_shared<CStoreFieldOperation>(FieldDescription);
                            LeftSideDescription.StoreLeftSideOperations.Add(StoreField);

                        }
                        else
                        {
                            auto LoadField = std::make_shared<CLoadFieldOperation>(FieldDescription);
                            LeftSideDescription.LoadLeftSideOperations.Add(LoadField);

                            auto StoreField = std::make_shared<CStoreFieldOperation>(FieldDescription);
                            LeftSideDescription.OnlyStoreLeftSideOperations.Add(StoreField);

                        }

                        break;
                    }
                    else if(auto PropertyDescription=ClassDescription->FindProperty(IdentifierName))
                    {
                        //LeftSideType=PropertyDescription->Type;
                        LeftSideDescription.LeftSideType=PropertyDescription->Type;

                        //set property
                        auto SetFunction=PropertyDescription->Setter;

                        if(!SetFunction)
                        {
                            InContext->GetFunction()->FileContext->RaiseError(20071,IdentifierNode->Identifier,U"property \'" + IdentifierName + U"\' do not have setter");
                            return SExpressionDerivationResult::Failed();
                        }

                        //consider both load and store
                        if(BothLoadAndStoreLeftSide)
                        {
                            //duplicate the field owner
                            auto DuplicateOperation=std::make_shared<CSimpleInstructionOperation>(EByteCodeInstructions::Duplicate);
                            LeftSideDescription.LoadLeftSideOperations.Add(DuplicateOperation);
                            
                            if(!PropertyDescription->Getter)
                            {
                                //raise error
                                InContext->GetFunction()->FileContext->RaiseError(200120,IdentifierNode->Identifier,U"property \'" + IdentifierName + U"\' do not have getter");
                                return SExpressionDerivationResult::Failed();
                            }
                            
                            auto LoadProperty=std::make_shared<CFunctionCallOperation>(PropertyDescription->Getter);
                            LeftSideDescription.LoadLeftSideOperations.Add(LoadProperty);
                            
                        }
                        else
                        {
                            auto StoreProperty=std::make_shared<CFunctionCallOperation>(SetFunction);
                            LeftSideDescription.OnlyStoreLeftSideOperations.Add(StoreProperty);
                        }
                    
                        break;
                    }
                    else
                    {
                        //raise error, undefined idenfitier
                        InContext->GetFunction()->FileContext->RaiseError(20070,IdentifierNode->Identifier,U"left side identifier \'" + IdentifierName + U"\' is not assignable");
                        return SExpressionDerivationResult::Failed();
                    }


                }
                break;

                default:
                {
                    //raise error, only support identifier/function call access now
                    InContext->GetFunction()->FileContext->RaiseError(20071,LastNode->GetFirstToken(),U"left side is not assignable");
                    return SExpressionDerivationResult::Failed();
                
                }


            }
        }
        else if (MemberAccessResult.ClassLimitation)
        {
            //last node is static field of class 

            auto LastNode=MemberAccessNode->AccessChain[MemberAccessNode->AccessChain.Num()-1];

            if(LastNode->Type!=EASTNodeType::Identifier)
            {
                InContext->GetFunction()->FileContext->RaiseError(20072,LastNode->GetFirstToken(),U"left side is not assignable");
                return SExpressionDerivationResult::Failed();
            }

            auto IdentifierNode=std::static_pointer_cast<CIdentifierNode>(LastNode);

            auto IdentifierName=IdentifierNode->Identifier->ToString();

            std::shared_ptr<CTypeDescription> ClassDescription=MemberAccessResult.ClassLimitation;

            //search field
            if(auto FieldDescription=FindFieldByName(ClassDescription,IdentifierName))
            {
                if(!FieldDescription->Decorator->bIsStatic)
                {
                    InContext->GetFunction()->FileContext->RaiseError(20073,IdentifierNode->Identifier,U"assign non-static field \'" + IdentifierName + U"\' need a instance");
                    return SExpressionDerivationResult::Failed();
                }

                //remove operation after first operation,
                //because static field do not need load this
                AssignResult.Operations.Clear();

                LeftSideDescription.LeftSideType=FieldDescription->Type;

                {
                    auto StoreField=std::make_shared<CStoreFieldOperation>(FieldDescription);
                    LeftSideDescription.OnlyStoreLeftSideOperations.Add(StoreField);
                    LeftSideDescription.StoreLeftSideOperations.Add(StoreField);
                }

                {
                    auto LoadField=std::make_shared<CLoadFieldOperation>(FieldDescription);
                    LeftSideDescription.LoadLeftSideOperations.Add(LoadField);
                }
            }
            else
            {
                //raise error, undefined idenfitier
                InContext->GetFunction()->FileContext->RaiseError(20073,IdentifierNode->Identifier,U"left side identifier \'" + IdentifierName + U"\' is not assignable");
                return SExpressionDerivationResult::Failed();
            }
        }
        else
        {
            InContext->GetFunction()->FileContext->RaiseError(20074,InNode->LeftOperand->GetFirstToken(),U"left side is not assignable");
            return SExpressionDerivationResult::Failed();
        }
    }
    else {
        //raise error, only support identifier/function call access now
        InContext->GetFunction()->FileContext->RaiseError(20075,InNode->LeftOperand->GetFirstToken(),U"left side is not assignable");
        return SExpressionDerivationResult::Failed();
    } 

    auto AssignResult2=
        DerivationAssignExpressionWithLeftDescription(
            InContext
            ,LeftSideDescription
            ,InNode->RightOperand
            ,InNode->Operator->Type
            ,InNode->Operator
        );
    if(!AssignResult2.IsSucceed())
    {
        return SExpressionDerivationResult::Failed();
    }

    AssignResult.Operations.Append(AssignResult2.Operations);
    AssignResult.Type=AssignResult2.Type;

    return AssignResult;

DonotSupportAssign:
    InContext->GetFunction()->FileContext->RaiseError(20116,InNode->Operator, U"operator \'"+InNode->Operator->ToString()+U"\' is not supported for type");
    return SExpressionDerivationResult::Failed();

}

CSemanticAnalyzer::SExpressionDerivationResult CSemanticAnalyzer::DerivationAssignExpressionWithLeftDescription(
    std::shared_ptr<CExpressionContext> InContext
    , const SLeftSideDescription &LeftSideDescription
    , std::shared_ptr<CExpressionNode> InRight
    , EScriptTokenType InOperatorType 
    ,std::shared_ptr<CScriptToken> ErrorToken)
{
    assert(Token::IsAssignOperator(InOperatorType) && "only assign operator is supported");

    SExpressionDerivationResult AssignResult;

    auto RightExpressionContext=InContext->NewSubExpression();
    if(LeftSideDescription.LeftSideType.BasicType->IsDelegate())
    {
        RightExpressionContext->ExpectedTypes.Add(LeftSideDescription.LeftSideType);
    }

    auto RightSideResult=DerivationExpression(RightExpressionContext,InRight);
    if(!RightSideResult.IsSucceed())
    {
        return SExpressionDerivationResult::Failed();
    }

    SStaticConvertResult ConvertResult;
    //2.convert to left
    // if(LeftSideDescription.LeftSideType.Class->IsDelegate()
    // && RightSideResult.Type.Class->IsFunctionPointer())
    // {
    //     //skip convert,because 
    // }
    // else
    {
        ConvertResult=StaticConvertTo(
            InContext->GetFunction()
            ,LeftSideDescription.LeftSideType
            ,RightSideResult.Type
            ,InRight->GetFirstToken()
        );
        if(!ConvertResult.IsSucceed())
        {
            return SExpressionDerivationResult::Failed();
        }
    }

    if(InOperatorType==EScriptTokenType::Assign)
    {
        AssignResult.Operations.Append(RightSideResult.Operations);
        AssignResult.Operations.Append(ConvertResult.Operations);
        AssignResult.Operations.Append(LeftSideDescription.OnlyStoreLeftSideOperations);
    }
    else
    {
        //operator


        SExpressionDerivationResult OperatorResult;
        if(LeftSideDescription.LeftSideType.BasicType->IsDelegate())
        {
            std::shared_ptr<CFunctionDescription> OperatorFunction;

            if(InOperatorType==EScriptTokenType::PlusAssign)
            {
                // if(RightSideResult.Type.Class->IsFunctionPointer())
                // {
                //     OperatorFunction=LeftSideDescription.LeftSideType.Class->DelegateBindFunctionPointerFunction;
                // }
                // else
                {
                    OperatorFunction=LeftSideDescription.LeftSideType.BasicType->GetDelegateAppendFunction();
                }
            }
            else if(InOperatorType==EScriptTokenType::MinusAssign)
            {
                // if(RightSideResult.Type.Class->IsFunctionPointer())
                // {
                //     OperatorFunction=LeftSideDescription.LeftSideType.Class->DelegateUnbindFunctionPointerFunction;
                // }
                // else
                {
                    OperatorFunction=LeftSideDescription.LeftSideType.BasicType->GetDelegateRemoveFunction();
                }
            }
            else
            {
                InContext->GetFunction()->FileContext->RaiseError(20117,ErrorToken, U"only =/+=/-= assign operator is supported for delegate");
                return SExpressionDerivationResult::Failed();
            }

            //append/remove operator function
            auto InvokeOperatorFunction=std::make_shared<CFunctionCallOperation>(OperatorFunction);
            OperatorResult.Operations.Add(InvokeOperatorFunction);
            OperatorResult.Type=LeftSideDescription.LeftSideType;
        }
        else
        {
            EBinocularOperatorType OperatorType;

            switch(InOperatorType)
            {
                case EScriptTokenType::PlusAssign:
                {
                    OperatorType=EBinocularOperatorType::Plus;
                    break;
                }
                case EScriptTokenType::MinusAssign:
                {
                    OperatorType=EBinocularOperatorType::Minus;
                    break;
                }
                case EScriptTokenType::MultiplyAssign:
                {
                    OperatorType=EBinocularOperatorType::Multiply;
                    break;
                }
                case EScriptTokenType::DivideAssign:
                {
                    OperatorType=EBinocularOperatorType::Divide;
                    break;
                }
                case EScriptTokenType::ModAssign:
                {
                    OperatorType=EBinocularOperatorType::Mod;
                    break;
                }
                case EScriptTokenType::AndAssign:
                {
                    OperatorType=EBinocularOperatorType::BitAnd;
                    break;
                }
                case EScriptTokenType::OrAssign:
                {
                    OperatorType=EBinocularOperatorType::BitOr;
                    break;
                }
                case EScriptTokenType::XorAssign:
                {
                    OperatorType=EBinocularOperatorType::BitXor;
                    break;
                }
                case EScriptTokenType::LeftShiftAssign:
                {
                    OperatorType=EBinocularOperatorType::BitLeftShift;
                    break;
                }
                case EScriptTokenType::RightShiftAssign:
                {
                    OperatorType=EBinocularOperatorType::BitRightShift;
                    break;
                }
                default:
                {
                    assert(false&& "cant reach here, all assign operator should be handled before");
                }
            }

            OperatorResult=DerivationBinocularOperatorExpressionAfterLoaded(
                InContext
                ,LeftSideDescription.LeftSideType
                ,RightSideResult.Type
                ,OperatorType
                ,ErrorToken
            );
            if(!OperatorResult.IsSucceed())
            {
                return SExpressionDerivationResult::Failed(); 
            }
        }

        AssignResult.Operations.Append(LeftSideDescription.LoadLeftSideOperations);
        AssignResult.Operations.Append(RightSideResult.Operations);
        AssignResult.Operations.Append(ConvertResult.Operations);
        AssignResult.Operations.Append(OperatorResult.Operations);
        AssignResult.Operations.Append(LeftSideDescription.StoreLeftSideOperations);
    }
    AssignResult.Type=LeftSideDescription.LeftSideType;
    return AssignResult;
}

CSemanticAnalyzer::SExpressionDerivationResult 
CSemanticAnalyzer::DerivationInitializeFieldExpression(
    std::shared_ptr<CExpressionContext> InContext
    , std::shared_ptr<CGSharpFieldDescription> InFiled
    , std::shared_ptr<CExpressionNode> InRight
    , std::shared_ptr<CScriptToken> ErrorToken)
{
    SExpressionDerivationResult FieldAssignResult;

    SLeftSideDescription LeftSideDescription;

    if(!InFiled->IsStatic())
    {
        auto LoadThis= std::make_shared<CLoadArgumentOperation>(0);
        FieldAssignResult.Operations.Add(LoadThis);
    }

    //store field to stack
    auto StoreField = std::make_shared<CStoreFieldOperation>(InFiled);
    LeftSideDescription.OnlyStoreLeftSideOperations.Add(StoreField);        

    LeftSideDescription.LeftSideType=InFiled->Type;

    auto AssignResult2=
        DerivationAssignExpressionWithLeftDescription(
            InContext
            ,LeftSideDescription
            ,InRight
            ,EScriptTokenType::Assign
            ,ErrorToken
        );

    if(!AssignResult2.IsSucceed())
    {
        return SExpressionDerivationResult::Failed();
    }

    FieldAssignResult.Operations.Append(AssignResult2.Operations);
    FieldAssignResult.Type=AssignResult2.Type;

    return FieldAssignResult;
}

CSemanticAnalyzer::SExpressionDerivationResult CSemanticAnalyzer::DerivationTypeCastExpression(std::shared_ptr<CExpressionContext> InContext, std::shared_ptr<CTypeCastNode> InTypeCastNode)
{
    SExpressionDerivationResult TypeCastResult;

    auto TargetTypeResult=DerivationTypeNode(InContext->GetFunction(),InTypeCastNode->Type);
    if(!TargetTypeResult.IsSucceed())
    {
        return SExpressionDerivationResult::Failed();
    }

    if(TargetTypeResult.bIsVar)
    {
        InContext->GetFunction()->FileContext->RaiseError(20159,InTypeCastNode->GetFirstToken(),U"cant cast to var type");
        return SExpressionDerivationResult::Failed();
    }

    TypeCastResult.Type=TargetTypeResult.Type;

    if(!TypeCastResult.Type.IsValid())
    {
        InContext->GetFunction()->FileContext->RaiseError(20160,InTypeCastNode->GetFirstToken(),U"is not a type name");
        return SExpressionDerivationResult::Failed();
    }

    auto SourceResult=DerivationExpression(InContext->NewSubExpression(),InTypeCastNode->Expression);
    if(!SourceResult.IsSucceed())
    {
        return SExpressionDerivationResult::Failed();
    }
    TypeCastResult.Operations.Append(SourceResult.Operations);

    auto TargetType=TypeCastResult.Type;
    auto SourceType=SourceResult.Type;

    if(IsStaticConvertable(
        TargetType
        ,SourceType))
    {
        auto ConvertionResult=
            StaticConvertTo(InContext->GetFunction(),TargetType,SourceType,InTypeCastNode->GetFirstToken());
        
        if(!ConvertionResult.IsSucceed())
        {
            return SExpressionDerivationResult::Failed();
        }
        TypeCastResult.Operations.Append(ConvertionResult.Operations);
        return TypeCastResult;
    }

    //try dynamic convert
    if(TargetType.BasicType->IsClass() 
    && SourceType.BasicType->IsClass()
    && TargetType.BasicType->IsA(SourceType.BasicType)
    )
    {
        auto DynamicCastOperation=std::make_shared<CDynamicCastClassOperation>(TargetType.BasicType);
        TypeCastResult.Operations.Add(DynamicCastOperation);
        return TypeCastResult;
    }
    else
    {
        //raise error
        InContext->GetFunction()->FileContext->RaiseError(20158,InTypeCastNode->GetFirstToken(),U"cant convert type \'"+SourceType.BasicType->GetSearchName()+U"\' to type \'"+TargetType.BasicType->GetSearchName()+U"\'");
        return SExpressionDerivationResult::Failed();
    }

}

CSemanticAnalyzer::SExpressionDerivationResult CSemanticAnalyzer::DerivationPositiveExpression(std::shared_ptr<CExpressionContext> InContext, std::shared_ptr<CPositiveNode> InNode)
{
    auto ValueResult=DerivationExpression(InContext->NewSubExpression(),InNode->Value);
    if(!ValueResult.IsSucceed())
    {
        return SExpressionDerivationResult::Failed();
    }

    if(ValueResult.Type.BasicType->InnerType.HasValue())
    {
        if(WH::IsNumberType(ValueResult.Type.BasicType->InnerType.GetValue()))
        {
            return ValueResult;
        }
    }
    
    //raise error , only support number now
    InContext->GetFunction()->FileContext->RaiseError(20100,InNode->GetFirstToken(),U"operator \'+\' can only apply to number type");
    return SExpressionDerivationResult::Failed();
}

CSemanticAnalyzer::SExpressionDerivationResult CSemanticAnalyzer::DerivationNegativeExpression(std::shared_ptr<CExpressionContext> InContext, std::shared_ptr<CNegativeNode> InNode)
{
    auto ValueResult=DerivationExpression(InContext->NewSubExpression(),InNode->Value);
    if(!ValueResult.IsSucceed())
    {
        return SExpressionDerivationResult::Failed();
    }



    if(ValueResult.Type.BasicType->InnerType.HasValue())
    {
        if(WH::IsNumberType(ValueResult.Type.BasicType->InnerType.GetValue()))
        {
            //add negitive instruction for different type
            EByteCodeInstructions Instruction;

            switch(ValueResult.Type.BasicType->InnerType.GetValue())
            {
                case EScriptInnerType::Int8:
                {
                    Instruction=EByteCodeInstructions::Negative_i8;
                    break;
                }

                case EScriptInnerType::Int16:
                {
                    Instruction=EByteCodeInstructions::Negative_i16;
                    break;
                }

                case EScriptInnerType::Int32:
                {
                    Instruction=EByteCodeInstructions::Negative_i32;
                    break;
                }

                case EScriptInnerType::Int64:
                {
                    Instruction=EByteCodeInstructions::Negative_i64;
                    break;
                }

                case EScriptInnerType::Uint8:
                {
                    Instruction=EByteCodeInstructions::Negative_u8;
                    break;
                }

                case EScriptInnerType::Uint16:
                {
                    Instruction=EByteCodeInstructions::Negative_u16;
                    break;
                }

                case EScriptInnerType::Uint32:
                {
                    Instruction=EByteCodeInstructions::Negative_u32;
                    break;
                }

                case EScriptInnerType::Uint64:
                {
                    Instruction=EByteCodeInstructions::Negative_u64;
                    break;
                }
                case EScriptInnerType::Float:
                {
                    Instruction=EByteCodeInstructions::Negative_f32;
                    break;
                }

                case EScriptInnerType::Double:
                {
                    Instruction=EByteCodeInstructions::Negative_f64;
                    break;
                }

                default:
                {
                    assert(false && "not support type");
                    break;
                }
            }            

            auto NegativeOperation=std::make_shared<CSimpleInstructionOperation>(Instruction);
            
            ValueResult.Operations.Add(NegativeOperation);
            return ValueResult;
        }
    }

    //raise error , only support number now
    InContext->GetFunction()->FileContext->RaiseError(20101,InNode->GetFirstToken(),U"operator \'-\' can only apply to number type");
    return SExpressionDerivationResult::Failed();
}

CSemanticAnalyzer::SExpressionDerivationResult CSemanticAnalyzer::DerivationParenthesesExpression(std::shared_ptr<CExpressionContext> InContext, std::shared_ptr<CParenthesesNode> InNode)
{
    return DerivationExpression(InContext->NewSubExpression(),InNode->Expression);
}

CSemanticAnalyzer::STypeDerivationResult CSemanticAnalyzer::DerivationTypeNodeWithNameScope(std::shared_ptr<CScriptFileContext> InFileContext, const SNameScopeInCompile &InNameScope, std::shared_ptr<CTypeNode> InTypeNode)
{
    //there is 2 stages:
    //1.find basic type by namechain
    //2.try generalize class
    STypeDerivationResult TypeResult;
    TypeResult.bIsSucceed=true;
    TypeResult.Type= SDecoratedTypeDescription();

    std::shared_ptr<CTypeDescription> Class;

    //1.find basic type by namechain
    {
        auto InnerTypeResult= DerivationInnerTypeNode(InTypeNode);
        if(InnerTypeResult.HasValue())
        {
            auto InnerTypeResultValue=InnerTypeResult.GetValue();
            if(InnerTypeResultValue.bIsVar)
            {
                if(!InTypeNode->GenericTypes.Empty())
                {
                    InFileContext->RaiseError(20191,InTypeNode->GetFirstToken(),U"cant use var type as generic type argument or function return value");
                    return STypeDerivationResult::Failed();
                }

                return InnerTypeResultValue;
            }

            Class=InnerTypeResultValue.Type.BasicType;
        }
        else
        {
            //find class by namechain
            SNameScopeInCompile NameScope=InNameScope;
            for(int NameChianIndex=0; NameChianIndex< InTypeNode->NameChain.Num(); NameChianIndex++)
            {
                auto Name = InTypeNode->NameChain[NameChianIndex]->ToString();

                auto SubNameScopeResult=NameScope.FindSubNameScope(InFileContext,Name);

                if(!SubNameScopeResult.HasValue())
                {
                    InFileContext->RaiseError(20013,InTypeNode->NameChain[NameChianIndex],U"can't find type\""+Name+U"\", it is not a class or namespace" );
                    return STypeDerivationResult::Failed();
                }

                NameScope=SubNameScopeResult.GetValue();
            }

            if(!NameScope.IsClass())
            {
                //raise error
                InFileContext->RaiseError(20014,InTypeNode->NameChain[InTypeNode->NameChain.Num()-1],U"\""+InTypeNode->NameChain[InTypeNode->NameChain.Num()-1]->ToString()+U"\" is not a class,it is a namespace" );
                return STypeDerivationResult::Failed();
            }

            Class=NameScope.GetClass();
        }
    }
    TypeResult.Type.BasicType=Class;

    //2.try generalize class

    if(Class&&Class->IsGeneric()&& InTypeNode->GenericTypes.Num()==0)
    {
        //raise error
        InFileContext->RaiseError(20015,InTypeNode->NameChain[InTypeNode->NameChain.Num()-1],U"\""+InTypeNode->NameChain[InTypeNode->NameChain.Num()-1]->ToString()+U"\" is a generic class, you must provide generic type arguments" );
        return STypeDerivationResult::Failed();
    }
    else if((!Class||!Class->IsGeneric())&& InTypeNode->GenericTypes.Num()>0)
    {
        //raise error
        InFileContext->RaiseError(20016,InTypeNode->NameChain[InTypeNode->NameChain.Num()-1],U"\""+InTypeNode->NameChain[InTypeNode->NameChain.Num()-1]->ToString()+U"\" is not a generic class, you can't provide generic type arguments" );
        return STypeDerivationResult::Failed();
    }
    //generalize class
    if(InTypeNode->GenericTypes.Num()>0)
    {
        //1. find generic type arguments
        SGenericTypeArgumentGroup GenericTypeArgumentGroup;
        bool bCanGenerialize=true;
        for(auto GenericTypeNode : InTypeNode->GenericTypes)
        {
            auto GenericType = DerivationTypeNodeWithNameScope(InFileContext,InNameScope,GenericTypeNode);
            if(!GenericType.IsSucceed())
            {
                return STypeDerivationResult::Failed();
            }

            if(GenericType.bIsVar)
            {
                InFileContext->RaiseError(20190,GenericTypeNode->GetFirstToken(),U"cant use var type as generic type argument");
                return STypeDerivationResult::Failed();
            }

            GenericTypeArgumentGroup.Arguments.Add(GenericType.Type);

            if(GenericType.Type.BasicType->IsGenericPlaceholder())
            {
                bCanGenerialize=false;
            }

        }

        //2. find generalized type
        if(bCanGenerialize)
        {
            auto GeneralizedClass = 
                FindOrCreateScriptGenerializedClass(Class,GenericTypeArgumentGroup,Context);
            TypeResult.Type.BasicType=GeneralizedClass;
        }
        else
        {
            //cant generialize be cause there is a generic placeholder
            TypeResult.Type.BasicType=Class;
            for(auto &GenericTypeArgument : GenericTypeArgumentGroup.Arguments)
            {
                TypeResult.Type.OverrideGenericClasses.Add(GenericTypeArgument.BasicType);
            }

        }

    }

    return TypeResult;
}

CSemanticAnalyzer::STypeDerivationResult CSemanticAnalyzer::DerivationTypeNodeWithClass(std::shared_ptr<CScriptFileContext> InFileContext, std::shared_ptr<CTypeDescription> InNamescope, std::shared_ptr<CTypeNode> InTypeNode)
{
    return DerivationTypeNodeWithNameScope(InFileContext,SNameScopeInCompile::Create(InNamescope),InTypeNode);   
}

CSemanticAnalyzer::STypeDerivationResult CSemanticAnalyzer::DerivationTypeNodeWithNamespace(std::shared_ptr<CScriptFileContext> InFileContext, std::shared_ptr<CNamespaceDescription> InNamescope, std::shared_ptr<CTypeNode> InTypeNode)
{
    return DerivationTypeNodeWithNameScope(InFileContext,SNameScopeInCompile::Create(InNamescope),InTypeNode);
}

CSemanticAnalyzer::STypeDerivationResult CSemanticAnalyzer::DerivationTypeNode(std::shared_ptr<CFunctionContext> InFunction, std::shared_ptr<CTypeNode> InNode)
{
    return DerivationTypeNodeWithClass(InFunction->FileContext,InFunction->GetOwnerClass(),InNode);
}

TOptional<CSemanticAnalyzer::STypeDerivationResult> CSemanticAnalyzer::DerivationInnerTypeNode(std::shared_ptr<CTypeNode> InTypeNode)
{
    STypeDerivationResult TypeResult;
    TypeResult.bIsSucceed=true;

    if(InTypeNode->IsVoidType())
    {
        TypeResult.Type=VoidTypeDescription;
        return TypeResult;
    }

    if(InTypeNode->IsVarType())
    {
        TypeResult.bIsVar=true;
        return TypeResult;
    }

    TypeResult.Type= SDecoratedTypeDescription();

    assert(InTypeNode->NameChain.Num()>0);

    //check if it is a inner type
    if(InTypeNode->NameChain.Num()==1)
    {
        auto Name = InTypeNode->NameChain[0];
        if(Name->Type==EScriptTokenType::InnerType)
        {
            EScriptInnerType InnerType = Name->InnerType.GetValue();    
            TypeResult.Type.BasicType = GetInnerTypeClassDescription(InnerType);
            return TypeResult;
        }
    }

    return NullOpt;
}

CSemanticAnalyzer::SExpressionDerivationResult CSemanticAnalyzer::DerivationBinocularOperatorExpressionAfterLoaded(std::shared_ptr<CExpressionContext> InContext, SDecoratedTypeDescription InLeftType, SDecoratedTypeDescription InRightType, EBinocularOperatorType InOperatorType, std::shared_ptr<CScriptToken> InErrorToken)
{
    assert(false&& "unimplemented");
    return SExpressionDerivationResult::Failed();
}

CSemanticAnalyzer::SExpressionDerivationResult CSemanticAnalyzer::DerivationNewExpression(std::shared_ptr<CExpressionContext> InContext, std::shared_ptr<CNewNode> InNode)
{
    SExpressionDerivationResult NewResult;

    auto NewTypeResult=  DerivationTypeNode(InContext->GetFunction(),InNode->Type);
    if(!NewTypeResult.IsSucceed())
    {
        return SExpressionDerivationResult::Failed();
    }

    if(NewTypeResult.bIsVar)
    {
        InContext->GetFunction()->FileContext->RaiseError(20186,InNode->GetFirstToken(),U"can not create a var type");
        return SExpressionDerivationResult::Failed();
    }

    //SDecoratedTypeDescription ReturnValue=NewTypeResult.Type;
    NewResult.Type=NewTypeResult.Type;
    
    if(!NewResult.Type.IsValid())
    {
        //failed to derive type
        return SExpressionDerivationResult::Failed();
    }


    std::shared_ptr<CVariableDescription> TempVariable;
    if(NewResult.Type.IsValueType())
    {
        //create a anonymous object and init it

        //1.create a anonymous object
        TempVariable= InContext->GetSentence()->OcuppyOrAddAnonymousVariable(NewResult.Type);
        
    }

    TVector<std::shared_ptr<CExpressionContext>> ArgumentContexts;
    for(auto Argument:InNode->Arguments)
    {
        ArgumentContexts.Add(InContext->NewSubExpression());
    }

    TVector<std::shared_ptr<CConstructorDescription>> ConstructorDescriptions;
    TVector<TVector<SDecoratedTypeDescription>> ArgumentTypes;
    if(NewResult.Type.BasicType->IsDelegate())
    {
        if(ArgumentContexts.Num()!=1)
        {
            InContext->GetFunction()->FileContext->RaiseError(20194
                ,InNode->GetFirstToken()
                ,U"invoke delegate constructor need 1 argument(a function)");
            return SExpressionDerivationResult::Failed();
        }
        //ArgumentContexts[0]->ExpectedTypes.Add(ReturnValue->Class->DelegateFunctionPointerType);
        ConstructorDescriptions.Add(NewResult.Type.BasicType->GetDelegateConstructorByFunctionPointer());
        TVector<SDecoratedTypeDescription> Arguments=
            {NewResult.Type};
        ArgumentTypes.Add(Arguments);
    }
    else
    {
        for(auto& Constructor: NewResult.Type.BasicType->Constructors)
        {
            if(Constructor->Parameters.Num()!=InNode->Arguments.Num()
                || Constructor->bIsStatic
            )
            {
                continue;
            }

            ConstructorDescriptions.Add(Constructor);
            
            TVector<SDecoratedTypeDescription> Arguments;
            for(auto& Parameter: Constructor->Parameters)
            {
                Arguments.Add(Parameter->Type);
            }
            ArgumentTypes.Add(Arguments);
        }

        if(ConstructorDescriptions.Empty())
        {
            if(NewResult.Type.BasicType->IsValueType()
                && InNode->Arguments.Empty()
            ) 
            {
                //.load Variable at head
                auto LoadVariableAddress= std::make_shared<CLoadVariableAddressOperation>(TempVariable,nullptr);
                NewResult.Operations.Add(LoadVariableAddress);

                //init value type
                auto Init= std::make_shared<CInitValueTypeOperation>(NewResult.Type.BasicType);
                NewResult.Operations.Add(Init);

                //load Variable value
                auto LoadVariable= std::make_shared<CLoadVariableOperation>(TempVariable,nullptr);
                NewResult.Operations.Add(LoadVariable);

                return NewResult;
            }
            else
            {
                //raise Error , no constructor found
                InContext->GetFunction()->FileContext->RaiseError(20198
                    ,InNode->GetFirstToken()
                    ,CString(U"no constructor require ") 
                    +CString(InNode->Arguments.Num())
                    + U" Parameters"
                    + U" found for type \'"
                    + NewResult.Type.BasicType->GetSearchName()
                    + U"\'"
                    );
                return SExpressionDerivationResult::Failed();
            }

           
        }
    }


    auto ArgumentResult=DerivationFunctionArugments(
        ArgumentContexts
        ,ArgumentTypes
        ,InNode->Arguments
        ,InNode->GetFirstToken()
    );

    if(!ArgumentResult.IsSucceed())
    {
        return SExpressionDerivationResult::Failed();
    }
    NewResult.Operations.Append(ArgumentResult.Operations);

    //if it is a delegate, just return the loaded delegate
    //because expecte type is delegate
    if(NewResult.Type.BasicType->IsDelegate())
    {
        return NewResult;        
    }

    //find constructor
    std::shared_ptr<CConstructorDescription> ConstructorDescription=
        ConstructorDescriptions[ArgumentResult.FunctionIndex];

    // determine use new object , init object or call constructor
    if(NewResult.Type.IsValueType())
    {
        assert(TempVariable);

        //.load Variable at head
        auto LoadVariableAddress= std::make_shared<CLoadVariableAddressOperation>(TempVariable);
        NewResult.Operations.Insert(0,LoadVariableAddress);

        auto DuplicateOperation=std::make_shared<CSimpleInstructionOperation>(EByteCodeInstructions::Duplicate);
        NewResult.Operations.Insert(1,DuplicateOperation);

        auto Init= std::make_shared<CInitValueTypeOperation>(NewResult.Type.BasicType);
        NewResult.Operations.Insert(2,Init);

        //construct object
        auto ConstructValueType= std::make_shared<CConstructorCallOperation>(ConstructorDescription);
        NewResult.Operations.Add(ConstructValueType);

        //load Variable value
        auto LoadVariable= std::make_shared<CLoadVariableOperation>(TempVariable);
        NewResult.Operations.Add(LoadVariable);
        
    }
    else
    {
        //new object
        NewResult.Operations.Add(std::make_shared<CNewObjectOperation>(NewResult.Type.BasicType ,ConstructorDescription));
    }
    

    return NewResult;

}

CSemanticAnalyzer::SSentenceDerivationResult CSemanticAnalyzer::DerivationVariableDeclarationNode(
    std::shared_ptr<CFunctionContext> InFunction
    ,std::shared_ptr<CStatementContext> InParentSentence
    ,std::shared_ptr<CVariableDeclarationNode > InNode
    )
{
    auto DeclarationVariableSentence= InFunction->NewSentence(
        InParentSentence
        ,EStatementType::VariableDeclaration
        );
    
    SSentenceDerivationResult Result;
    Result.bSuccess=true;
    Result.StatementContext=DeclarationVariableSentence;

    //create variable 
    CString VariableName=InNode->Name->ToString();
    auto PredefinedVariablePosition= DeclarationVariableSentence
        ->TestVariableName(VariableName);
    if(PredefinedVariablePosition.HasValue())
    {
        //raise error, variable already defined
        InFunction->FileContext->RaiseError(20157,InNode->Name,U"variable \'" + VariableName + U"\' already defined");
        return SSentenceDerivationResult::Failed();
    }

    auto VariableTypeResult= DerivationTypeNode(InFunction,InNode->Type);
    if(!VariableTypeResult.IsSucceed())
    {
        return SSentenceDerivationResult::Failed();
    }

    if(VariableTypeResult.bIsVar && !InNode->InitialValue)
    {
        InFunction->FileContext->RaiseError(20156,InNode->Name,U"declarariopn variable with type \'var\' need initial value");
        return SSentenceDerivationResult::Failed();
    }

    auto VariableType= VariableTypeResult.Type;

    if(VariableType.IsSameWith(VoidTypeDescription))
    {
        InFunction->FileContext->RaiseError(20060,
            InNode->Type->GetFirstToken(),
            U"variable type can not be \'void\'");
        return SSentenceDerivationResult::Failed();
    }


    //derivation right side
    if(InNode->InitialValue)
    {
        auto ExpressionContext=DeclarationVariableSentence->NewExpression(nullptr);

        if(VariableType.IsValid()&&VariableType.BasicType->IsDelegate())
        {
            ExpressionContext->ExpectedTypes.Add(VariableType.BasicType->DelegateFunctionPointerType);
        }

        auto InitialValueResult=DerivationExpression(
            ExpressionContext
            ,InNode->InitialValue);
        if(!InitialValueResult.IsSucceed())
        {
            return SSentenceDerivationResult::Failed();
        }

        //try derivation type of variable
        if(!VariableType.IsValid())
        {
            assert(VariableTypeResult.bIsVar);
            VariableType=InitialValueResult.Type;
        }

        auto Variable =DeclarationVariableSentence->AddVariable(VariableType,VariableName);
      
        auto ConvertResult=StaticConvertTo(
            InFunction
            ,VariableType
            ,InitialValueResult.Type
            ,InNode->InitialValue->GetFirstToken());
        if(!ConvertResult.IsSucceed())
        {
            return SSentenceDerivationResult::Failed();
        }

        //store to left side
        auto StoreVariable=std::make_shared<CStoreVariableOperation>(Variable);
        
        Result.Operations.Append(InitialValueResult.Operations);
        Result.Operations.Append(ConvertResult.Operations);
        Result.Operations.Add(StoreVariable);
        
    }
    else
    {
        auto Variable =DeclarationVariableSentence->AddVariable(VariableType,VariableName);

    }


    return Result;

}

CSemanticAnalyzer::SSentenceDerivationResult CSemanticAnalyzer::DerivationReturnStatement(
    std::shared_ptr<CFunctionContext> InFunction
    ,std::shared_ptr<CStatementContext> InParentSentence
    ,std::shared_ptr<CReturnNode> InNode)
{
    auto ReturnSentence= InFunction->NewSentence(
        InParentSentence
        ,EStatementType::Return
        );

    SSentenceDerivationResult ReturnResult;
    ReturnResult.bSuccess=true;
    ReturnResult.StatementContext=ReturnSentence;

    if(InNode->Value)
    {
        
        auto ReturnValueResult=
            DerivationExpression(ReturnSentence->NewExpression(nullptr)
            ,InNode->Value);
        if(!ReturnValueResult.IsSucceed())
        {
            return SSentenceDerivationResult::Failed();
        }

        auto ConvertResult=StaticConvertTo(
            InFunction
            ,InFunction->ReturnType
            ,ReturnValueResult.Type
            ,InNode->GetFirstToken());
        if(!ConvertResult.IsSucceed())
        {
            return SSentenceDerivationResult::Failed();
        }

        ReturnResult.Operations.Append(ReturnValueResult.Operations);
        ReturnResult.Operations.Append(ConvertResult.Operations);

    }
    else
    {
        if(!InFunction->ReturnType.IsSameWith(VoidTypeDescription))
        {
            InFunction->FileContext->RaiseError(20059,InNode->GetFirstToken(),U"function must return a value");
            return SSentenceDerivationResult::Failed();
        }
    }

    ReturnResult.Operations.Add(std::make_shared<CReturnOperation>());
    return ReturnResult;
}

CSemanticAnalyzer::SSentenceDerivationResult CSemanticAnalyzer::DerivationIfStatement(
    std::shared_ptr<CFunctionContext> InFunction
    , std::shared_ptr<CStatementContext> InParentSentence
    , std::shared_ptr<CIfNode> InNode)
{
    auto IfSentence= InFunction->NewSentence(
        InParentSentence
        ,EStatementType::If
        );
    SSentenceDerivationResult IfResult;
    IfResult.bSuccess=true;
    IfResult.StatementContext=IfSentence;

    auto ConditionResult=DerivationExpression(
        IfSentence->NewExpression(nullptr)
        ,InNode->Condition);
    if(!ConditionResult.IsSucceed())
    {
        return SSentenceDerivationResult::Failed();
    }

    auto ConvertToBoolResult=StaticConvertTo(
        InFunction
        ,BoolTypeDescription
        ,ConditionResult.Type
        ,InNode->Condition->GetFirstToken());
    if(!ConvertToBoolResult.IsSucceed())
    {
        return SSentenceDerivationResult::Failed();
    }

    auto TrueBranchResult=DerivationSentenceBlock(InFunction,IfSentence,InNode->TrueBranch);
    if(!TrueBranchResult.IsSucceed())
    {
        return SSentenceDerivationResult::Failed();
    }

    SSentenceDerivationResult FalseBranchResult;
    if(InNode->FalseBranch)
    {
        FalseBranchResult=DerivationSentenceBlock(InFunction,IfSentence,InNode->FalseBranch);
        if(!FalseBranchResult.IsSucceed())
        {
            return SSentenceDerivationResult::Failed();
        }
    }

    //combine operations
    //1.append Contion operations and convert to bool operations
    IfResult.Operations.Append(ConditionResult.Operations);
    IfResult.Operations.Append(ConvertToBoolResult.Operations);

    //2. add a jump operation
    auto ConditionJumpOperation= std::make_shared<CJumpOperation>();
    ConditionJumpOperation->Condition= CJumpOperation::EJumpCondition::IfFalse;
    IfResult.Operations.Add(ConditionJumpOperation);

    //3. append true branch operations
    IfResult.Operations.Append(TrueBranchResult.Operations);

    if(!FalseBranchResult.Operations.Empty())
    {
        //add jump to end after true branch
        auto JumpToEndOperation= std::make_shared<CJumpOperation>();
        JumpToEndOperation->Condition= CJumpOperation::EJumpCondition::Always;
        IfResult.Operations.Add(JumpToEndOperation);

        //4.append false branch
        IfResult.Operations.Append(FalseBranchResult.Operations);
        ConditionJumpOperation->JumpTo=FalseBranchResult.Operations[0];

        auto EndOperation= std::make_shared<CDoNothingOperation>();
        JumpToEndOperation->JumpTo=EndOperation;
        IfResult.Operations.Add(EndOperation);
    }
    else
    {
        //4.add a  operation as end 
        auto EndOperation= std::make_shared<CDoNothingOperation>();
        IfResult.Operations.Add(EndOperation);
        ConditionJumpOperation->JumpTo=EndOperation;
    }

    return IfResult;
}

CSemanticAnalyzer::SSentenceDerivationResult CSemanticAnalyzer::DerivationWhileStatement(
    std::shared_ptr<CFunctionContext> InFunction
    ,std::shared_ptr<CStatementContext> InParentSentence
    , std::shared_ptr<CWhileNode> InNode)
{
    auto WhileSentence= InFunction->NewSentence(
        InParentSentence
        ,EStatementType::While
        );

    SSentenceDerivationResult WhileResult;
    WhileResult.bSuccess=true;
    WhileResult.StatementContext=WhileSentence;

    auto ConditionResult= DerivationExpression(
        WhileSentence->NewExpression(nullptr)
        ,InNode->Condition);
    if(!ConditionResult.IsSucceed())
    {
        return SSentenceDerivationResult::Failed();
    }

    auto ConvertToBoolResult=StaticConvertTo(
        InFunction
        ,BoolTypeDescription
        ,ConditionResult.Type
        ,InNode->Condition->GetFirstToken());
    if(!ConvertToBoolResult.IsSucceed())
    {
        return SSentenceDerivationResult::Failed();
    }



    //combine operations
    //1. add a operation before condition as jump target
    auto OperationBeforeCondition= std::make_shared<CDoNothingOperation>();
    WhileResult.Operations.Add(OperationBeforeCondition);

    //2. append condition operations and convert to bool operations
    WhileResult.Operations.Append(ConditionResult.Operations);
    WhileResult.Operations.Append(ConvertToBoolResult.Operations);

    //3. add a jump operation, jump to end of loop body
    auto JumpToEndOperation= std::make_shared<CJumpOperation>();
    JumpToEndOperation->Condition= CJumpOperation::EJumpCondition::IfFalse;


    //the operation after loop body
    auto EndOperation= std::make_shared<CDoNothingOperation>();
    //4. append loop body operations
    InFunction->BreakJumpTargets.push(EndOperation);
    InFunction->LoopContinueJumpTargets.push(OperationBeforeCondition);
    auto LoopBodyResult= DerivationSentenceBlock(InFunction,WhileSentence,InNode->Body);
    if(!LoopBodyResult.IsSucceed())
    {
        return SSentenceDerivationResult::Failed();
    }
    InFunction->LoopContinueJumpTargets.pop();
    InFunction->BreakJumpTargets.pop();

    WhileResult.Operations.Append(LoopBodyResult.Operations);

    //5. add a jump operation, jump to line before condition
    auto JumpToConditionOperation= std::make_shared<CJumpOperation>();
    JumpToConditionOperation->Condition= CJumpOperation::EJumpCondition::Always;
    JumpToConditionOperation->JumpTo=OperationBeforeCondition;

    //6. add a operation as end
    
    JumpToEndOperation->JumpTo=EndOperation;
    WhileResult.Operations.Add(EndOperation);

    return WhileResult;
}

CSemanticAnalyzer::SSentenceDerivationResult 
    CSemanticAnalyzer::DerivationDoWhileStatement(
        std::shared_ptr<CFunctionContext> InFunctionContext
        , std::shared_ptr<CStatementContext> InParentStatementContext
        , std::shared_ptr<CDoWhileNode> InNode)
{
    auto DoWhileSentence= InFunctionContext->NewSentence(
        InParentStatementContext
        ,EStatementType::DoWhile
        );
        
    SSentenceDerivationResult DoWhileResult;
    DoWhileResult.bSuccess=true;
    DoWhileResult.StatementContext=DoWhileSentence;


    //the operation before loop body, if condition is true , jump to this
    auto OperationBeforeLoopBody= std::make_shared<CDoNothingOperation>();

    //the operation before condition, if continue , jump to this
    auto OperationBeforeCondition= std::make_shared<CDoNothingOperation>();

    //the operation at end, if break jump to this
    auto EndOperation= std::make_shared<CDoNothingOperation>();

    //derivation loop body
    InFunctionContext->BreakJumpTargets.push(EndOperation);
    InFunctionContext->LoopContinueJumpTargets.push(OperationBeforeLoopBody);
    auto LoopBodyResult= DerivationSentenceBlock(InFunctionContext,DoWhileSentence,InNode->Body);

    if(!LoopBodyResult.IsSucceed())
    {
        return SSentenceDerivationResult::Failed();
    }

    InFunctionContext->LoopContinueJumpTargets.pop();
    InFunctionContext->BreakJumpTargets.pop();

    //derivation condition
    auto ConditionResult= DerivationExpression(
        DoWhileSentence->NewExpression(nullptr)
        ,InNode->Condition);

    if(!ConditionResult.IsSucceed())
    {
        return SSentenceDerivationResult::Failed();
    }

    auto ConvertToBoolResult=StaticConvertTo(
        InFunctionContext
        ,BoolTypeDescription
        ,ConditionResult.Type
        ,InNode->Condition->GetFirstToken());

    if(!ConvertToBoolResult.IsSucceed())
    {
        return SSentenceDerivationResult::Failed();
    }

    //combine operations
    //1. add a operation before loop body as jump target
    DoWhileResult.Operations.Add(OperationBeforeLoopBody);

    //2. append loop body operations
    DoWhileResult.Operations.Append(LoopBodyResult.Operations);

    //3. add a operation before condition as jump target
    DoWhileResult.Operations.Add(OperationBeforeCondition);

    //4. append condition operations and convert to bool operations
    DoWhileResult.Operations.Append(ConditionResult.Operations);
    DoWhileResult.Operations.Append(ConvertToBoolResult.Operations);

    //5. add a jump operation, jump to before loop body
    auto JumpToLoopBodyOperation= std::make_shared<CJumpOperation>();
    JumpToLoopBodyOperation->Condition= CJumpOperation::EJumpCondition::IfTrue;
    JumpToLoopBodyOperation->JumpTo=OperationBeforeLoopBody;
    DoWhileResult.Operations.Add(JumpToLoopBodyOperation);

    //6. add a operation as end
    DoWhileResult.Operations.Add(EndOperation);

    return DoWhileResult;

}

CSemanticAnalyzer::SSentenceDerivationResult 
    CSemanticAnalyzer::DerivationBreakStatement(
    std::shared_ptr<CFunctionContext> InFunction
    ,std::shared_ptr<CStatementContext> InParentSentence
    , std::shared_ptr<CBreakNode> InNode)
{
    //check if in loop by BreakJumpTargets
    if(InFunction->BreakJumpTargets.empty())
    {
        InFunction->FileContext->RaiseError(20062,InNode->GetFirstToken(),U"break must be in a loop");
        return SSentenceDerivationResult::Failed();
    }

    auto JumpOperation= std::make_shared<CJumpOperation>();
    JumpOperation->JumpTo=InFunction->BreakJumpTargets.top();
    JumpOperation->Condition=CJumpOperation::EJumpCondition::Always;

    SSentenceDerivationResult BreakResult;
    BreakResult.bSuccess=true;
    BreakResult.StatementContext= InFunction->NewSentence(
        InParentSentence,EStatementType::Break);

    BreakResult.Operations.Add(JumpOperation);

    return BreakResult;
}

CSemanticAnalyzer::SSentenceDerivationResult 
    CSemanticAnalyzer::DerivationContinueStatement(
    std::shared_ptr<CFunctionContext> InFunction
    ,std::shared_ptr<CStatementContext> InParentSentence
    , std::shared_ptr<CContinueNode> InNode)
{
    //check if in loop by BreakJumpTargets
    if(InFunction->BreakJumpTargets.empty())
    {
        InFunction->FileContext->RaiseError(20063,InNode->GetFirstToken(),U"continue must be in a loop");
        return SSentenceDerivationResult::Failed();
    }

    auto JumpOperation= std::make_shared<CJumpOperation>();
    JumpOperation->JumpTo=InFunction->LoopContinueJumpTargets.top();
    JumpOperation->Condition=CJumpOperation::EJumpCondition::Always;

    SSentenceDerivationResult ContinueResult;
    ContinueResult.bSuccess=true;
    ContinueResult.StatementContext=
        InFunction->NewSentence(InParentSentence,EStatementType::Continue);

    ContinueResult.Operations.Add(JumpOperation);

    return ContinueResult;

}

CSemanticAnalyzer::SExpressionDerivationResult CSemanticAnalyzer::DerivationMonocularExpression(std::shared_ptr<CExpressionContext> InContext, std::shared_ptr<CMonocularOperatorNode> InNode)
{
    SExpressionDerivationResult MonocularResult;

    auto CreateAddOrSubOperation=[](bool IsAdd,EScriptInnerType InNumberType)
    {
        EByteCodeInstructions Instruction;
        if(IsAdd)
        {
            switch(InNumberType)
            {
                case EScriptInnerType::Int8:
                    Instruction=EByteCodeInstructions::Add_i8;
                    break;
                case EScriptInnerType::Int16:
                    Instruction=EByteCodeInstructions::Add_i16;
                    break;
                case EScriptInnerType::Int32:
                    Instruction=EByteCodeInstructions::Add_i32;
                    break;
                case EScriptInnerType::Int64:
                    Instruction=EByteCodeInstructions::Add_i64;
                    break;
                case EScriptInnerType::Uint8:
                    Instruction=EByteCodeInstructions::Add_u8;
                    break;
                case EScriptInnerType::Uint16:
                    Instruction=EByteCodeInstructions::Add_u16;
                    break;
                case EScriptInnerType::Uint32:
                    Instruction=EByteCodeInstructions::Add_u32;
                    break;
                case EScriptInnerType::Uint64:
                    Instruction=EByteCodeInstructions::Add_u64;
                    break;
                case EScriptInnerType::Float:
                    Instruction=EByteCodeInstructions::Add_f32;
                    break;
                case EScriptInnerType::Double:
                    Instruction=EByteCodeInstructions::Add_f64;
                    break;
                default:
                    assert(false && "unimplement");
                    break;
            }
        }
        else
        {
            switch(InNumberType)
            {
                case EScriptInnerType::Int8:
                    Instruction=EByteCodeInstructions::Sub_i8;
                    break;
                case EScriptInnerType::Int16:
                    Instruction=EByteCodeInstructions::Sub_i16;
                    break;
                case EScriptInnerType::Int32:
                    Instruction=EByteCodeInstructions::Sub_i32;
                    break;
                case EScriptInnerType::Int64:
                    Instruction=EByteCodeInstructions::Sub_i64;
                    break;
                case EScriptInnerType::Uint8:
                    Instruction=EByteCodeInstructions::Sub_u8;
                    break;
                case EScriptInnerType::Uint16:
                    Instruction=EByteCodeInstructions::Sub_u16;
                    break;
                case EScriptInnerType::Uint32:
                    Instruction=EByteCodeInstructions::Sub_u32;
                    break;
                case EScriptInnerType::Uint64:
                    Instruction=EByteCodeInstructions::Sub_u64;
                    break;
                case EScriptInnerType::Float:
                    Instruction=EByteCodeInstructions::Sub_f32;
                    break;
                case EScriptInnerType::Double:
                    Instruction=EByteCodeInstructions::Sub_f64;
                    break;
                default:
                    assert(false && "unimplement");
                    break;
            }
        }

        return std::make_shared<CSimpleInstructionOperation>(Instruction);
    };

    auto CreateLoadLiteral1Operation=[this](EScriptInnerType InNumberType)
    {
        switch(InNumberType)
        {
            case EScriptInnerType::Int8:
                return std::make_shared<CLoadLiteralOperation>(
                    (int8_t)1 ,GetInnerTypeClassDescription(EScriptInnerType::Int8)); 
            case EScriptInnerType::Int16:
                return std::make_shared<CLoadLiteralOperation>(
                    (int16_t)1 ,GetInnerTypeClassDescription(EScriptInnerType::Int16));
            case EScriptInnerType::Int32:
                return std::make_shared<CLoadLiteralOperation>(
                    (int32_t)1 ,GetInnerTypeClassDescription(EScriptInnerType::Int32));
            case EScriptInnerType::Int64:
                return std::make_shared<CLoadLiteralOperation>(
                    (int64_t)1 ,GetInnerTypeClassDescription(EScriptInnerType::Int64));
            case EScriptInnerType::Uint8:
                return std::make_shared<CLoadLiteralOperation>(
                    (uint8_t)1 ,GetInnerTypeClassDescription(EScriptInnerType::Uint8));
            case EScriptInnerType::Uint16:
                return std::make_shared<CLoadLiteralOperation>(
                    (uint16_t)1 ,GetInnerTypeClassDescription(EScriptInnerType::Uint16));
            case EScriptInnerType::Uint32:
                return std::make_shared<CLoadLiteralOperation>(
                    (uint32_t)1 ,GetInnerTypeClassDescription(EScriptInnerType::Uint32));
            case EScriptInnerType::Uint64:
                return std::make_shared<CLoadLiteralOperation>(
                    (uint64_t)1 ,GetInnerTypeClassDescription(EScriptInnerType::Uint64));
            case EScriptInnerType::Float:
                return std::make_shared<CLoadLiteralOperation>(
                    (float)1 ,GetInnerTypeClassDescription(EScriptInnerType::Float));
            case EScriptInnerType::Double:
                return std::make_shared<CLoadLiteralOperation>(
                    (double)1 ,GetInnerTypeClassDescription(EScriptInnerType::Double));
            default:
                assert(false && "unimplement");
                break;
        }

        assert(false && "unreachable");
        return std::shared_ptr<CLoadLiteralOperation>();
    };

    //derivation operand
    if(InNode->Operand->Type==EASTNodeType::MemberAccess)
    {
        auto MemberAccessNode=std::static_pointer_cast<CMemberAccessNode>(InNode->Operand);

        //derivation except last node
        auto MemberAccessResult=DerivationMemberAccessExpression(InContext,MemberAccessNode,true);
        MonocularResult.Operations.Append(MemberAccessResult.Operations);

        if(!MemberAccessResult.Type.IsValid())
        {   
            //error occured
            return SExpressionDerivationResult::Failed();
        }
        
        if(MemberAccessResult.Type.IsValid())
        {
            //last node is field or property or indexer
            auto LastNode=MemberAccessNode->AccessChain[MemberAccessNode->AccessChain.Num()-1];

            if(LastNode->Type==EASTNodeType::Identifier)
            {
                //last node is identifier
                auto IdentifierNode=std::static_pointer_cast<CIdentifierNode>(LastNode);
                auto IdentifierName=IdentifierNode->Identifier->ToString();

                std::shared_ptr<CTypeDescription> ClassDescription=MemberAccessResult.Type.BasicType;
            
                //search field
                if(auto FieldDescription=FindFieldByName(ClassDescription,IdentifierName))
                {
                    if(FieldDescription->IsStatic())
                    {
                        //remove operations after placeholder
                        //because static field do not need object
                        //user may use object to access static field
                        MonocularResult.Operations.Clear();
                    }

                    auto FieldType=FieldDescription->Type;

                    if(!FieldType.IsValid())
                    {
                        InContext->GetFunction()->FileContext->RaiseError(20076,IdentifierNode->Identifier,U"identifier \'" + IdentifierName + U"\' is not a field");
                        return SExpressionDerivationResult::Failed();                    }

                    if(!FieldType.BasicType->IsInnerType())
                    {
                        InContext->GetFunction()->FileContext->RaiseError(20077,IdentifierNode->Identifier,U"operator \'" + InNode->Operator->ToString() + U"\' is not defined for type \'" + FieldType.BasicType->GetSearchName() + U"\', only support inner type now");
                        return SExpressionDerivationResult::Failed();
                    }

                    EScriptInnerType InnerType=FieldType.BasicType->InnerType.GetValue();

                    if(!WH::IsNumberType(InnerType))
                    {
                        InContext->GetFunction()->FileContext->RaiseError(20078,IdentifierNode->Identifier,U"operator \'" + InNode->Operator->ToString() + U"\' is not defined for type \'" + FieldType.BasicType->GetSearchName() + U"\', only support number type now");
                        return SExpressionDerivationResult::Failed();
                    }

                    if(InNode->Operator->Type!=EScriptTokenType::PlusPlus
                        && InNode->Operator->Type!=EScriptTokenType::MinusMinus
                    )
                    {
                        InContext->GetFunction()->FileContext->RaiseError(20079,InNode->Operator,U"operator \'" + InNode->Operator->ToString() + U"\' is not defined for type \'" + FieldType.BasicType->GetSearchName() + U"\'");
                        return SExpressionDerivationResult::Failed();
                    }

                    //0. duplicate object value
                    auto DuplicateValueOperation=std::make_shared<CSimpleInstructionOperation>(EByteCodeInstructions::Duplicate);
                    MonocularResult.Operations.Add(DuplicateValueOperation);
                   
                    //1. load variable
                    auto LoadField=std::make_shared<CLoadFieldOperation>(FieldDescription);
                    MonocularResult.Operations.Add(LoadField);
                   
                    //2. load literal 1
                    std::shared_ptr<CLoadLiteralOperation> LoadLiteral=CreateLoadLiteral1Operation(InnerType);
                    MonocularResult.Operations.Add(LoadLiteral);

                    //3 + /-
                    auto AddOrSubOperation= CreateAddOrSubOperation(InNode->Operator->Type==EScriptTokenType::PlusPlus,InnerType);
                    MonocularResult.Operations.Add(AddOrSubOperation);
                    
                    //4.store to variable
                    auto StoreField=std::make_shared<CStoreFieldOperation>(FieldDescription);
                    MonocularResult.Operations.Add(StoreField);
                   
                    MonocularResult.Type=VoidTypeDescription;
                    return MonocularResult;
                }
                
                //search property
                if(auto PropertyDescription=ClassDescription->FindProperty(IdentifierName))
                {
                    auto PropertyType=PropertyDescription->Type;

                    if(!PropertyType.IsValid())
                    {
                        InContext->GetFunction()->FileContext->RaiseError(20080,IdentifierNode->Identifier,U"identifier \'" + IdentifierName + U"\' is not a property");
                        return SExpressionDerivationResult::Failed();
                    }

                    if(!PropertyType.BasicType->IsInnerType())
                    {
                        InContext->GetFunction()->FileContext->RaiseError(20081,IdentifierNode->Identifier,U"operator \'" + InNode->Operator->ToString() + U"\' is not defined for type \'" + PropertyType.BasicType->GetSearchName() + U"\', only support inner type now");
                        return SExpressionDerivationResult::Failed();
                    }

                    EScriptInnerType InnerType=PropertyType.BasicType->InnerType.GetValue();

                    if(!WH::IsNumberType(InnerType))
                    {
                        InContext->GetFunction()->FileContext->RaiseError(20082,IdentifierNode->Identifier,U"operator \'" + InNode->Operator->ToString() + U"\' is not defined for type \'" + PropertyType.BasicType->GetSearchName() + U"\', only support number type now");
                        return SExpressionDerivationResult::Failed();
                    }

                    if(InNode->Operator->Type!=EScriptTokenType::PlusPlus
                        && InNode->Operator->Type!=EScriptTokenType::MinusMinus
                    )
                    {
                        InContext->GetFunction()->FileContext->RaiseError(20083,InNode->Operator,U"operator \'" + InNode->Operator->ToString() + U"\' is not defined for type \'" + PropertyType.BasicType->GetSearchName() + U"\'");
                        return SExpressionDerivationResult::Failed();
                    }

                    //check if property have getter and setter
                    if(!PropertyDescription->Getter)
                    {
                        InContext->GetFunction()->FileContext->RaiseError(20084,IdentifierNode->Identifier,U"property \'" + IdentifierName + U"\' do not have getter");
                        return SExpressionDerivationResult::Failed();
                    }        

                    if(!PropertyDescription->Setter)
                    {
                        InContext->GetFunction()->FileContext->RaiseError(20085,IdentifierNode->Identifier,U"property \'" + IdentifierName + U"\' do not have setter");
                        return SExpressionDerivationResult::Failed();
                    }    
                    
                    //0. duplicate object value
                    auto DuplicateValueOperation=std::make_shared<CSimpleInstructionOperation>(EByteCodeInstructions::Duplicate);
                    MonocularResult.Operations.Add(DuplicateValueOperation);
                    
                    //1.invoke getter
                    auto GetFunction=PropertyDescription->Getter;
                    auto InvokeGetFunction=std::make_shared<CFunctionCallOperation>(GetFunction);
                    MonocularResult.Operations.Add(InvokeGetFunction);
                    
                    //2. load literal 1
                    std::shared_ptr<CLoadLiteralOperation> LoadLiteral=CreateLoadLiteral1Operation(InnerType);
                    MonocularResult.Operations.Add(LoadLiteral);
                    
                    //3 + /-
                    auto AddOrSubOperation= CreateAddOrSubOperation(InNode->Operator->Type==EScriptTokenType::PlusPlus,InnerType);
                    MonocularResult.Operations.Add(AddOrSubOperation);
                  
                    //4.invoke setter
                    auto SetFunction=PropertyDescription->Setter;
                    auto InvokeSetFunction=std::make_shared<CFunctionCallOperation>(SetFunction);
                    MonocularResult.Operations.Add(InvokeSetFunction);

                    MonocularResult.Type=VoidTypeDescription;
                    return MonocularResult;
                }

                //raise error, unsupported idenfitier
                InContext->GetFunction()->FileContext->RaiseError(20086,IdentifierNode->Identifier,U"identifier \'" + IdentifierName + U"\' is not a field or property");
                return SExpressionDerivationResult::Failed();
            }
            else if(LastNode->Type==EASTNodeType::SentenceIndexer)
            {
                assert(false && "unimplement");
                return SExpressionDerivationResult::Failed();
            }
            else
            {
                //raise error, unsupported idenfitier
                InContext->GetFunction()->FileContext->RaiseError(20087,LastNode->GetFirstToken(),U"operator \'" + InNode->Operator->ToString() + U"\' is not defined for type \'" + MemberAccessResult.Type.BasicType->GetSearchName() + U"\'");
                return SExpressionDerivationResult::Failed();
            
            }
        }
        else if(MemberAccessResult.ClassLimitation)
        {
            //last node is static field of class
            assert(false && "unimplement");
            return SExpressionDerivationResult::Failed();
        }
        else
        {
            //raise error, not assignable
            InContext->GetFunction()->FileContext->RaiseError(20088,InNode->Operand->GetFirstToken(),U"not assignable");
            return SExpressionDerivationResult::Failed();
        
        }
    }
    else if(InNode->Operand->Type==EASTNodeType::Identifier)
    {
        //get Identifier name
        auto IdentifierNode=std::static_pointer_cast<CIdentifierNode>(InNode->Operand);
        CString IdentifierName=IdentifierNode->Identifier->ToString();
        
        //detect identifier is local variable
        if(auto Variable= InContext->GetSentence()->FindVariableByName(IdentifierName))
        {
            auto VariableType=Variable->Type;

            if(!VariableType.IsValid())
            {
                InContext->GetFunction()->FileContext->RaiseError(20089,InNode->Operand->GetFirstToken(),U"identifier \'" + IdentifierName + U"\' is not a variable");
                return SExpressionDerivationResult::Failed();
            }

            if(!VariableType.BasicType->IsInnerType())
            {
                InContext->GetFunction()->FileContext->RaiseError(20090,InNode->Operand->GetFirstToken(),U"operator \'" + InNode->Operator->ToString() + U"\' is not defined for type \'" + VariableType.BasicType->GetSearchName() + U"\', only support inner type now");
                return SExpressionDerivationResult::Failed();
            }

            EScriptInnerType InnerType=VariableType.BasicType->InnerType.GetValue();

            if(!WH::IsNumberType(InnerType))
            {
                InContext->GetFunction()->FileContext->RaiseError(20091,InNode->Operand->GetFirstToken(),U"operator \'" + InNode->Operator->ToString() + U"\' is not defined for type \'" + VariableType.BasicType->GetSearchName() + U"\', only support number type now");
                return SExpressionDerivationResult::Failed();
            }

            if(InNode->Operator->Type!=EScriptTokenType::PlusPlus
                && InNode->Operator->Type!=EScriptTokenType::MinusMinus
            )
            {
                InContext->GetFunction()->FileContext->RaiseError(20092,InNode->Operator,U"operator \'" + InNode->Operator->ToString() + U"\' is not defined for type \'" + VariableType.BasicType->GetSearchName() + U"\'");
                return SExpressionDerivationResult::Failed();
            }

            //1. load variable
            auto LoadVariable=std::make_shared<CLoadVariableOperation>(Variable);
            MonocularResult.Operations.Add(LoadVariable);
            
            //2. load literal 1
            std::shared_ptr<CLoadLiteralOperation> LoadLiteral=CreateLoadLiteral1Operation(InnerType);
            MonocularResult.Operations.Add(LoadLiteral);
            
            //3 + /-
            auto AddOrSubOperation= CreateAddOrSubOperation(InNode->Operator->Type==EScriptTokenType::PlusPlus,InnerType);
            MonocularResult.Operations.Add(AddOrSubOperation);
           
            //4.store to variable
            auto StoreVariable=std::make_shared<CStoreVariableOperation>(Variable);
            MonocularResult.Operations.Add(StoreVariable);
           
            MonocularResult.Type=VoidTypeDescription;
            return MonocularResult;
        }

        //detect identifier is parameter
        if(auto Parameter= InContext->GetSentence()->FindParameterByName(IdentifierName))
        {
            auto ParameterType=Parameter->Type;

            if(!ParameterType.IsValid())
            {
                InContext->GetFunction()->FileContext->RaiseError(20093,InNode->Operand->GetFirstToken(),U"identifier \'" + IdentifierName + U"\' is not a parameter");
                return SExpressionDerivationResult::Failed();
            }

            if(!ParameterType.BasicType->IsInnerType())
            {
                InContext->GetFunction()->FileContext->RaiseError(20094,InNode->Operand->GetFirstToken(),U"operator \'" + InNode->Operator->ToString() + U"\' is not defined for type \'" + ParameterType.BasicType->GetSearchName() + U"\', only support inner type now");
                return SExpressionDerivationResult::Failed();
            }

            EScriptInnerType InnerType=ParameterType.BasicType->InnerType.GetValue();

            if(!WH::IsNumberType(InnerType))
            {
                InContext->GetFunction()->FileContext->RaiseError(20095,InNode->Operand->GetFirstToken(),U"operator \'" + InNode->Operator->ToString() + U"\' is not defined for type \'" + ParameterType.BasicType->GetSearchName() + U"\', only support number type now");
                return SExpressionDerivationResult::Failed();
            }

            if(InNode->Operator->Type!=EScriptTokenType::PlusPlus
                && InNode->Operator->Type!=EScriptTokenType::MinusMinus
            )
            {
                InContext->GetFunction()->FileContext->RaiseError(20096,InNode->Operator,U"operator \'" + InNode->Operator->ToString() + U"\' is not defined for type \'" + ParameterType.BasicType->GetSearchName() + U"\'");
                return SExpressionDerivationResult::Failed();
            }

            //1. load variable
            auto LoadParameter=std::make_shared<CLoadArgumentOperation>(Parameter->ArgumentIndex);
            MonocularResult.Operations.Add(LoadParameter);

            //2. load literal 1
            std::shared_ptr<CLoadLiteralOperation> LoadLiteral=CreateLoadLiteral1Operation(InnerType);
            MonocularResult.Operations.Add(LoadLiteral);
            
            //3 + /-
            auto AddOrSubOperation= CreateAddOrSubOperation(InNode->Operator->Type==EScriptTokenType::PlusPlus,InnerType);
            MonocularResult.Operations.Add(AddOrSubOperation);
            
            //4.store to variable
            auto StoreParameter=std::make_shared<CStoreArgumentOperation>(Parameter->ArgumentIndex);
            MonocularResult.Operations.Add(StoreParameter);

            MonocularResult.Type=VoidTypeDescription;
            return MonocularResult;
        }

        //detect identifier is field
        if(auto FieldDescription=InContext->GetSentence()->FindFieldByName(IdentifierName))
        {
            auto FieldType=FieldDescription->Type;

            if(!FieldType.IsValid())
            {
                InContext->GetFunction()->FileContext->RaiseError(20097,InNode->Operand->GetFirstToken(),U"identifier \'" + IdentifierName + U"\' is not a field");
                return SExpressionDerivationResult::Failed();
            }

            if(!FieldType.BasicType->IsInnerType())
            {
                InContext->GetFunction()->FileContext->RaiseError(20098,InNode->Operand->GetFirstToken(),U"operator \'" + InNode->Operator->ToString() + U"\' is not defined for type \'" + FieldType.BasicType->GetSearchName() + U"\', only support inner type now");
                return SExpressionDerivationResult::Failed();
            }

            EScriptInnerType InnerType=FieldType.BasicType->InnerType.GetValue();

            if(!WH::IsNumberType(InnerType))
            {
                InContext->GetFunction()->FileContext->RaiseError(20099,InNode->Operand->GetFirstToken(),U"operator \'" + InNode->Operator->ToString() + U"\' is not defined for type \'" + FieldType.BasicType->GetSearchName() + U"\', only support number type now");
                return SExpressionDerivationResult::Failed();
            }

            if(InNode->Operator->Type!=EScriptTokenType::PlusPlus
                && InNode->Operator->Type!=EScriptTokenType::MinusMinus
            )
            {
                InContext->GetFunction()->FileContext->RaiseError(20115,InNode->Operator,U"operator \'" + InNode->Operator->ToString() + U"\' is not defined for type \'" + FieldType.BasicType->GetSearchName() + U"\'");
                return SExpressionDerivationResult::Failed();
            }

            //load this
            if(!FieldDescription->IsStatic())
            {
                auto LoadThis=std::make_shared<CLoadArgumentOperation>(0);
                MonocularResult.Operations.Add(LoadThis);
                
                //load this twice
                auto DuplicateThis=std::make_shared<CSimpleInstructionOperation>(EByteCodeInstructions::Duplicate);
                MonocularResult.Operations.Add(DuplicateThis);
            }

            //1. load variable
            auto LoadField=std::make_shared<CLoadFieldOperation>(FieldDescription);
            MonocularResult.Operations.Add(LoadField);
           
            //2. load literal 1
            std::shared_ptr<CLoadLiteralOperation> LoadLiteral=CreateLoadLiteral1Operation(InnerType);
            MonocularResult.Operations.Add(LoadLiteral);
            
            //3 + /-
            auto AddOrSubOperation= CreateAddOrSubOperation(InNode->Operator->Type==EScriptTokenType::PlusPlus,InnerType);
            MonocularResult.Operations.Add(AddOrSubOperation);
            
            //4.store to variable
            auto StoreField=std::make_shared<CStoreFieldOperation>(FieldDescription);
            MonocularResult.Operations.Add(StoreField);

            MonocularResult.Type=VoidTypeDescription;
            return MonocularResult;
        }


        InContext->GetFunction()->FileContext->RaiseError(20078,IdentifierNode->Identifier,U"identifier \'" + IdentifierName + U"\' is not defined");
        return SExpressionDerivationResult::Failed();
    }
    else
    {
        //raise error, token is not a left value
        InContext->GetFunction()->FileContext->RaiseError(20178
            ,InNode->Operand->GetFirstToken()
            ,U"left side is not assignable");
        return SExpressionDerivationResult::Failed();
    }

}

CSemanticAnalyzer::SSentenceDerivationResult CSemanticAnalyzer::DerivationForStatement(
    std::shared_ptr<CFunctionContext> InFunction
    , std::shared_ptr<CStatementContext> InParentSentence
    , std::shared_ptr<CForNode> InNode)
{

    auto ForSentence= InFunction->NewSentence(
        InParentSentence
        ,EStatementType::For
        );
    SSentenceDerivationResult ForResult;
    ForResult.bSuccess=true;
    ForResult.StatementContext=ForSentence;

    SSentenceDerivationResult InitResult;
    //1. init
    if(InNode->Init)
    {
        InitResult = DerivationSentence(InFunction,ForSentence,InNode->Init);
        if(!InitResult.IsSucceed())
        {
            return SSentenceDerivationResult::Failed();
        }
    }

    //2. condition
    SExpressionDerivationResult ConditionResult;
    

    if(InNode->Condition)
    {
        ConditionResult=DerivationExpression(
            ForSentence->NewExpression(nullptr)
            ,InNode->Condition);
        if(!ConditionResult.IsSucceed())
        {
            return SSentenceDerivationResult::Failed();
        }

        //convert to bool
        auto ConvertResult=StaticConvertTo(InFunction,BoolTypeDescription,ConditionResult.Type,InNode->Condition->GetFirstToken());
        if(!ConvertResult.IsSucceed())
        {
            return SSentenceDerivationResult::Failed();
        }
        ConditionResult.Operations.Append(ConvertResult.Operations);
    }

    //3. body

    auto LoopEndOperation= std::make_shared<CDoNothingOperation>();
    auto BeforeStep= std::make_shared<CDoNothingOperation>();
    InFunction->BreakJumpTargets.push(LoopEndOperation); //for keyword 'break'
    InFunction->LoopContinueJumpTargets.push(BeforeStep); //for keyword 'continue'

    auto BodyResult= DerivationSentenceBlock(InFunction,ForSentence,InNode->Body);
    if(!BodyResult.IsSucceed())
    {
        return SSentenceDerivationResult::Failed();
    }

    InFunction->LoopContinueJumpTargets.pop();
    InFunction->BreakJumpTargets.pop();

    //4. step
    SSentenceDerivationResult StepResult;
    if(InNode->Step)
    {
        StepResult= DerivationSentence(InFunction,ForSentence,InNode->Step);
        if(!StepResult.IsSucceed())
        {
            return SSentenceDerivationResult::Failed();
        }
    }

    //combine operations
    
    //1. add init
    ForResult.Operations.Append(InitResult.Operations);

    //2. add operation before condition
    auto OperationBeforeCondition= std::make_shared<CDoNothingOperation>();
    ForResult.Operations.Add(OperationBeforeCondition);

    //3. add condition
    if(InNode->Condition)
    {
        ForResult.Operations.Append(ConditionResult.Operations);

        auto JumpToEndOperation= std::make_shared<CJumpOperation>();
        JumpToEndOperation->JumpTo=LoopEndOperation;
        JumpToEndOperation->Condition=CJumpOperation::EJumpCondition::IfFalse;
    
        ForResult.Operations.Add(JumpToEndOperation);
    }

    //4. add body
    ForResult.Operations.Append(BodyResult.Operations);

    //5. add before step
    ForResult.Operations.Add(BeforeStep);

    //6. add step
    if(InNode->Step)
    {
        ForResult.Operations.Append(StepResult.Operations);
    }

    //7. jump to operation before condition
    {
        auto JumpOperation= std::make_shared<CJumpOperation>();
        JumpOperation->JumpTo=OperationBeforeCondition;
        JumpOperation->Condition=CJumpOperation::EJumpCondition::Always;
        ForResult.Operations.Add(JumpOperation);
    }

    //8. add end
    ForResult.Operations.Add(LoopEndOperation);

    return ForResult;
}

CSemanticAnalyzer::SSentenceDerivationResult CSemanticAnalyzer::DerivationSwitchStatement(
    std::shared_ptr<CFunctionContext> InFunction
    ,std::shared_ptr<CStatementContext> InParentSentence 
    , std::shared_ptr<CSwitchNode> InNode)
{
    auto SwitchSentence = InFunction->NewSentence(
        InParentSentence
        ,EStatementType::Switch
        );

    SSentenceDerivationResult SwitchResult;
    SwitchResult.bSuccess=true;
    SwitchResult.StatementContext=SwitchSentence;

    SExpressionDerivationResult ValueResult=
        DerivationExpression(
            SwitchSentence->NewExpression(nullptr)
            ,InNode->Value);
    if(!ValueResult.IsSucceed())
    {
        return SSentenceDerivationResult::Failed();
    }



    //default label index
    int32_t DefaultLabelIndex=-1;
    TVector<SExpressionDerivationResult> Labels; //include default label
    SDecoratedTypeDescription LabelType;
    TVector<SSentenceDerivationResult> Bodies;

    //help to find body index by label index, if label index is -1, 
    //use next case body index
    TVector<int32_t> BodyIndexs; 


    auto EndOfSwitchOperation= std::make_shared<CDoNothingOperation>();
    InFunction->BreakJumpTargets.push(EndOfSwitchOperation);
    for(int32_t CaseIndex=0; CaseIndex<InNode->Cases.Num(); CaseIndex++)
    {
        auto Case=InNode->Cases[CaseIndex];
        if(Case->Case->Type==EScriptTokenType::Default)
        {
            DefaultLabelIndex=CaseIndex;
            Labels.Emplace();
        }
        else
        {
            assert(Case->Condition.HasValue());

            auto LabelResult=DerivationExpression(
                SwitchSentence->NewExpression(nullptr)
                ,Case->Condition.GetValue());
            if(!LabelResult.IsSucceed())
            {
                return SSentenceDerivationResult::Failed();
            }

            if(!LabelType.IsValid())
            {
                LabelType=LabelResult.Type;
            }
            else
            {
                if(!LabelType.IsSameWith(LabelResult.Type))
                {
                    InFunction->FileContext->RaiseError(20122,InNode->GetFirstToken(),U"all case label must have same type");
                    return SSentenceDerivationResult::Failed();
                }
            }

            Labels.Add(LabelResult);
        }

        if(Case->Body)
        {
            auto BodyResult=DerivationSentenceBlock(InFunction,SwitchSentence,Case->Body);
            if(!BodyResult.IsSucceed())
            {
                return SSentenceDerivationResult::Failed();
            }
            Bodies.Add(BodyResult);

            auto BodyIndex=Bodies.Num()-1;
            BodyIndexs.Add(BodyIndex);

            //set former body indexs to this body index
            //if former body index is -1
            for(int32_t FormerLabelIndex=CaseIndex-1; FormerLabelIndex>=0; FormerLabelIndex--)
            {
                if(BodyIndexs[FormerLabelIndex]==-1)
                {
                    BodyIndexs[FormerLabelIndex]=BodyIndex;
                }
                else
                {
                    break;
                }
            }
        }
        else
        {
            BodyIndexs.Add(-1);
        }
        

        //check if last case have body
        if(CaseIndex==InNode->Cases.Num()-1 && !Case->Body)
        {
            //raise error, last case must have body
            InFunction->FileContext->RaiseError(20123,Case->Case,U"last case of switch cant be empty");
            return SSentenceDerivationResult::Failed();
        }
    }
    
    InFunction->BreakJumpTargets.pop();

    //combine operations
    //1. load value
    SwitchResult.Operations.Append(ValueResult.Operations);

    //convert to label type
    SDecoratedTypeDescription ValueType=ValueResult.Type;
    if(Labels.Num()>0)
    {
        auto ConvertResult=StaticConvertTo(InFunction,LabelType,ValueResult.Type,InNode->Value->GetFirstToken());
        if(!ConvertResult.IsSucceed())
        {
            return SSentenceDerivationResult::Failed();
        }
        SwitchResult.Operations.Append(ConvertResult.Operations);

        ValueType=LabelType;
    }

    //store value to temp variable
    auto TempVariable=SwitchSentence->OcuppyOrAddAnonymousVariable(ValueType);
    SwitchResult.Operations.Add(std::make_shared<CStoreVariableOperation>(TempVariable));

    //2. Generate jump table
    for(int32_t LabelIndex=0; LabelIndex<Labels.Num(); LabelIndex++)
    {
        int32_t BodyIndex = BodyIndexs[LabelIndex];
        assert(BodyIndex!=-1);

        auto JumpToBody= std::make_shared<CJumpOperation>();

        if(LabelIndex==DefaultLabelIndex)
        {
            JumpToBody->Condition=CJumpOperation::EJumpCondition::Always;
        }
        else
        {
            JumpToBody->Condition=CJumpOperation::EJumpCondition::IfEqual;
        
            //load value
            auto LoadVariable=std::make_shared<CLoadVariableOperation>(TempVariable);
            SwitchResult.Operations.Add(LoadVariable);


            //load label
            SwitchResult.Operations.Append(Labels[LabelIndex].Operations);
        }

        JumpToBody->JumpTo=Bodies[BodyIndex].Operations[0];
        SwitchResult.Operations.Add(JumpToBody);
    }

    //jump to end if no case match
    auto JumpToEnd= std::make_shared<CJumpOperation>();
    JumpToEnd->Condition=CJumpOperation::EJumpCondition::Always;
    JumpToEnd->JumpTo=EndOfSwitchOperation;
    SwitchResult.Operations.Add(JumpToEnd);

    //3. add cases body
    for(auto& Body: Bodies)
    {
        SwitchResult.Operations.Append(Body.Operations);
    }

    //4. add end
    SwitchResult.Operations.Add(EndOfSwitchOperation);

    return SwitchResult;
}

CSemanticAnalyzer::SSentenceDerivationResult CSemanticAnalyzer::DerivationExpressionSentence(
    std::shared_ptr<CFunctionContext> InFunction
    , std::shared_ptr<CStatementContext> InParentSentence
    , std::shared_ptr<CExpressionSentence> InNode)
{
    auto Sentence= InFunction->NewSentence(
        InParentSentence
        ,EStatementType::Expression
        );

    auto ExpressionResult=DerivationExpression(
        Sentence->NewExpression(nullptr)
    ,InNode->Expression);

    if(!ExpressionResult.IsSucceed())
    {
        return SSentenceDerivationResult::Failed();
    }

    SSentenceDerivationResult Result;
    Result.bSuccess=true;
    Result.Operations=ExpressionResult.Operations;
    Result.StatementContext=Sentence;

    return Result;
}

CSemanticAnalyzer::SExpressionDerivationResult CSemanticAnalyzer::DerivationValueExpression(std::shared_ptr<CExpressionContext> InContext, std::shared_ptr<CValueNode> InNode)
{
    if(InContext->GetFunction()->Parameters.Empty())
    {
        InContext->GetFunction()->FileContext->RaiseError(20068,InNode->GetFirstToken(),U" key word 'value' can only be used in Set accessor");
        return SExpressionDerivationResult::Failed();
    }

    uint32_t ArgumentIndex= InContext->GetFunction()->Parameters.Num()-1;
    auto Type= InContext->GetFunction()->Parameters[ArgumentIndex]->Type;

    //load argument
    SExpressionDerivationResult Result;
    Result.Type=Type;

    auto LoadArgument=std::make_shared<CLoadArgumentOperation>(1 /* This */ +ArgumentIndex);
    Result.Operations.Add(LoadArgument);

    return Result;
}

bool CSemanticAnalyzer::IsStaticConvertable(SDecoratedTypeDescription To
    ,SDecoratedTypeDescription From)
{
    if(To.BasicType==From.BasicType)
    {
        return true;
    }

    if(To.BasicType->IsClass() && From.BasicType->IsClass())
    {
        if(From.BasicType->IsA(To.BasicType))
        {
            return true;
        }
    }

    //try to convert function pointer to delegate
    if(From.BasicType->IsFunctionPointer()
        && To.BasicType->IsDelegate()
        && To.BasicType->DelegateFunctionPointerType.BasicType==From.BasicType)
    {
        return true;
    }

    if(To.BasicType == GetInnerTypeClassDescription(EScriptInnerType::Object))
    {   
        if(From.BasicType->GetIdentifierType()!=EIdentifierType::Class)
        {
            return false;
        }

        auto RightClassDescription=std::static_pointer_cast<CTypeDescription>(From.BasicType);

        if(RightClassDescription->IsInnerType())
        {
            // Box innner type
            return true;
        }

        else
        {
            assert(false && "unimplemented" );
            return true;
        }

    } 

    if(To.BasicType->IsInnerType() && From.BasicType->IsInnerType())
    {
        EScriptInnerType FromInnerType= From.BasicType->InnerType.GetValue();
        
        if(WH::IsNumberType(FromInnerType) 
        || (FromInnerType==EScriptInnerType::Bool)
        || (FromInnerType==EScriptInnerType::Char)
          )
        {
            EScriptInnerType ToInnerType= To.BasicType->InnerType.GetValue();

            if(WH::IsNumberType(ToInnerType) 
            || (ToInnerType==EScriptInnerType::Bool)
            || (ToInnerType==EScriptInnerType::Char)
            )
            {
                return true;
            }
        }
    }

    if(From.IsSameWith(NullObjectTypeDescription)
        && To.BasicType->IsClass()
    )
    {
        //null can be convert to any class
        return true;
    }

    if(From.IsSameWith(NullPtrTypeDescription)
        && To.BasicType->IsClass()
    )
    {
        //null can be convert to any class
        return true;
    }

    //try convert to Enum type
    if(To.BasicType->IsEnum())
    {
        return IsStaticConvertable(To.BasicType->EnumValueType,From);
    }
    else if(From.BasicType->IsEnum())
    {
        return IsStaticConvertable(To,From.BasicType->EnumValueType);
    }

    return false;
};

CSemanticAnalyzer::SStaticConvertResult CSemanticAnalyzer::StaticConvertTo(
        std::shared_ptr<CFunctionContext> InFunction
        ,SDecoratedTypeDescription To
        ,SDecoratedTypeDescription From
        ,std::shared_ptr<CScriptToken> ErrorToken)
{
    SStaticConvertResult Result;
    Result.bSuccess=true;


    if(To.BasicType==From.BasicType)
    {
        return Result;
    }

    //check Is left type is base of right type
    if(To.BasicType->IsClass() && From.BasicType->IsClass())
    {
        if(From.BasicType->IsA(To.BasicType))
        {
            return Result;
        }
    }

    //try to convert function pointer to delegate
    // if(From.Class->IsFunctionPointer()
    //     && To.Class->IsDelegate()
    //     && To.Class->DelegateFunctionPointerType.Class==From.Class)
    // {
    //     //init delegate   
    //     Result.Operations.Add(std::make_shared<CConstructorCallOperation>(To.Class->Constructors[0]));     
    //     return Result;
    // }

    if(To.BasicType == GetInnerTypeClassDescription(EScriptInnerType::Object))
    {   
        auto RightClassDescription=From.BasicType;

        if(RightClassDescription->IsInnerType())
        {
            // Box innner type
            Result.Operations.Add(std::make_shared<CBoxInnerTypeOperation>(From));
            return Result;
        }
        else
        {
            assert(false && "unimplemented" );
            return Result;
        }

    } 

    if(To.BasicType->IsInnerType() && From.BasicType->IsInnerType())
    {
        EScriptInnerType FromInnerType= From.BasicType->InnerType.GetValue();
        
        if(WH::IsNumberType(FromInnerType) 
        || (FromInnerType==EScriptInnerType::Bool)
        || (FromInnerType==EScriptInnerType::Char)
          )
        {
            EScriptInnerType ToInnerType= To.BasicType->InnerType.GetValue();

            if(WH::IsNumberType(ToInnerType) 
            || (ToInnerType==EScriptInnerType::Bool)
            || (ToInnerType==EScriptInnerType::Char)
            )
            {
                auto InnerTypeConvertionOperation=std::make_shared<CInnerTypeConvertionOperation>(FromInnerType,ToInnerType);
                Result.Operations.Add(InnerTypeConvertionOperation);
                return Result;
            }
        }
    }

    if(From.IsSameWith(NullObjectTypeDescription)
        && To.BasicType->IsClass()
    )
    {
        return Result;
    }

    if(From.IsSameWith(NullPtrTypeDescription)
        && To.BasicType->IsClass()
    )
    {
        //replace null ptr with null object
        Result.Operations.Add(std::make_shared<CSimpleInstructionOperation>(EByteCodeInstructions::Pop));
        Result.Operations.Add(std::make_shared<CSimpleInstructionOperation>(EByteCodeInstructions::LoadNullObject));

        //null can be convert to any class
        return Result;
    }

    if(To.BasicType->IsEnum())
    {
        return StaticConvertTo(InFunction,To.BasicType->EnumValueType,From,ErrorToken);
    }
    else if(From.BasicType->IsEnum())
    {
        return StaticConvertTo(InFunction,To,From.BasicType->EnumValueType,ErrorToken);
    }
    
    InFunction->FileContext->RaiseError(20069,ErrorToken ,U"Cant convert from type["+ From.BasicType->GetSearchName() +U"] To [" + To.BasicType->GetSearchName() +U"].");
    return SStaticConvertResult::Failed();
}

std::shared_ptr<CTypeDescription> CSemanticAnalyzer::GetInnerTypeClassDescription(EScriptInnerType InnerType)
{
    switch (InnerType)
    {
    case EScriptInnerType::Object:
        return ObjectDescription;
    case EScriptInnerType::String:
        return StringDescription;
    case EScriptInnerType::Int32:
        return Int32Description;
    case EScriptInnerType::Float:
        return FloatDescription;
    case EScriptInnerType::Bool:
        return BoolDescription;
    case EScriptInnerType::Void:
        return nullptr;
    case EScriptInnerType::NullPtr:
        return NullPtrDescription;
    case EScriptInnerType::NullObject:
        return NullObjectDescription;
    case EScriptInnerType::Int64:
        return Int64Description;
    case EScriptInnerType::Double:
        return DoubleDescription;
    case EScriptInnerType::Uint8:
        return ByteDescription;
    case EScriptInnerType::Char:
        return CharDescription;
    case EScriptInnerType::Int16:
        return ShortDescription;
    case EScriptInnerType::Uint32:
        return Uint32Description;
    case EScriptInnerType::Uint64:
        return Uint64Description;
    case EScriptInnerType::Uint16:
        return UshortDescription;
    case EScriptInnerType::Int8:
        return SbyteDescription;

    default:
        assert(false && "unimplemented");
        return nullptr;
    }

}

SDecoratedTypeDescription CSemanticAnalyzer::GetInnerTypeDescription(EScriptInnerType InnerType)
{
    switch (InnerType)
    {
    case EScriptInnerType::Object:
        return ObjectTypeDescription;
    case EScriptInnerType::String:
        return StringTypeDescription;
    case EScriptInnerType::Int32:
        return Int32TypeDescription;
    case EScriptInnerType::Float:
        return FloatTypeDescription;
    case EScriptInnerType::Bool:
        return BoolTypeDescription;
    case EScriptInnerType::Void:
        return VoidTypeDescription;
    case EScriptInnerType::NullPtr:
        return NullPtrTypeDescription;
    case EScriptInnerType::NullObject:
        return NullObjectTypeDescription;
    case EScriptInnerType::Int64:
        return Int64TypeDescription;
    case EScriptInnerType::Double:
        return DoubleTypeDescription;
    case EScriptInnerType::Uint8:
        return ByteTypeDescription;
    case EScriptInnerType::Char:
        return CharTypeDescription;
    case EScriptInnerType::Int16:
        return ShortTypeDescription;
    case EScriptInnerType::Uint32:
        return Uint32TypeDescription;
    case EScriptInnerType::Uint64:
        return Uint64TypeDescription;
    case EScriptInnerType::Uint16:
        return UshortTypeDescription;
    case EScriptInnerType::Int8:
        return SbyteTypeDescription;
    
    }

    assert(false && "unimplemented");
    return SDecoratedTypeDescription();
}

std::shared_ptr<CTypeDescription> CSemanticAnalyzer::FindClassByID(STypeID InTypeID)
{
    if(InTypeID.IsScriptType())
    {
        auto Ret=ScriptClasses[InTypeID];
        assert(Ret && "Script class not found");
        return Ret;
    }
    else
    {
        auto Ret=NativeClasses[InTypeID];
        assert(Ret && "Native class not found");
        return Ret;
    }
}

void CSemanticAnalyzer::AddScriptClass(std::shared_ptr<CTypeDescription> InClassDescription)
{
    assert(InClassDescription->TypeID.IsScriptType());

    assert(!ScriptClasses.Contains(InClassDescription->TypeID) && "Script class already exist");
    ScriptClasses.Add(InClassDescription->TypeID,InClassDescription);

    assert(!ScriptClassesInOrder.Contains(InClassDescription) && "Script class already exist in order");
    for(auto Class: ScriptClassesInOrder)
    {
        assert(Class->TypeID!=InClassDescription->TypeID && "Script class already exist in order");
    }
    ScriptClassesInOrder.Add(InClassDescription);
}

void CSemanticAnalyzer::MoveScriptClassOrderFormer(std::shared_ptr<CTypeDescription> Former, std::shared_ptr<CTypeDescription> After)
{
    if(Former==After)
    {
        return;
    }

    if(Former->IsNative()
        || After->IsNative())
    {
        return;
    }

    auto AfterIndex=ScriptClassesInOrder.IndexOf(After);
    auto FormerIndex=ScriptClassesInOrder.IndexOf(Former);
    
    if(AfterIndex.GetValue()<FormerIndex.GetValue())
    {
        ScriptClassesInOrder.RemoveAt(FormerIndex.GetValue());
        ScriptClassesInOrder.Insert(AfterIndex.GetValue(),Former);
    }
}

TOptional<CSemanticAnalyzer::SNameScopeInCompile> CSemanticAnalyzer::SNameScopeInCompile::FindSubNameScope(std::shared_ptr<CScriptFileContext> InFileContext, const CString & InName)
 {
    if(Namespace)
    {
        auto SubNamespace = Namespace->FindNamespaceInFile(InFileContext,InName);
        if(SubNamespace)
        {
            return SNameScopeInCompile::Create(SubNamespace);
        }
        else
        {
            auto Class=Namespace->FindClassInFile(InFileContext,InName);
            if(Class)
            {
                return SNameScopeInCompile::Create(Class);
            }
            else
            {
                return NullOpt;
            }
        }
    }
    else 
    {
        assert(Class);

        auto SubClass = Class->FindClassInFile(InFileContext,InName);
        if(SubClass)
        {
            return SNameScopeInCompile::Create(SubClass);
        }
        else
        {
            return NullOpt;
        }
    }
}
